Jak edytować dane pojedynczej pozycji na flatliście?

Do edytowania listy potrzebna jest nam… lista 🙂 Jeśli chcesz dowiedzieć się, jak stworzyć listę zadań, zobacz ten wpis: Renering list in React Native

Nasza lista zadań z powyższego wpisu prezentuje się tak:

React native FlatList scrolling


Dla przypomnienia, kod listy:

Data.js:

  
export default Data = [
{id: 1, text: 'Item One', color: 'red'},
{id: 2, text: 'Item Two', color: 'blue'},
{id: 3, text: 'Item Three', color: 'yellow'},
{id: 4, text: 'Item Four', color: 'green'},
{id: 5, text: 'Item Five', color: 'orange'},
{id: 6, text: 'Item Six', color: 'red'},
{id: 7, text: 'Item Seven', color: 'blue'},
{id: 8, text: 'Item Eight', color: 'yellow'},
{id: 9, text: 'Item Nine', color: 'green'},
{id: 10, text: 'Item Ten', color: 'orange'},
{id: 11, text: 'Item Eleven', color: 'red'},
{id: 12, text: 'Item Twelve', color: 'blue'},
{id: 13, text: 'Item Thirteen', color: 'yellow'},
{id: 14, text: 'Item Fourteen', color: 'green'},
{id: 15, text: 'Item Fifteen', color: 'orange'},
]

List.js:

 
import React, {Component} from 'react';
import {StyleSheet, Text, View, FlatList } from 'react-native';
import Data from './Data';

export default class List extends Component {

renderItem = ({item}) => (
<View style={styles.item}>
<View style={styles.marginLeft}>
<View style={[styles.menu, { backgroundColor: item.color }]}></View>
<View style={[styles.menu, { backgroundColor: item.color }]}></View>
<View style={[styles.menu, { backgroundColor: item.color }]}></View>
</View>
<Text style={styles.text}> {item.text} </Text>
</View>
)

render() {
return (
<View style={styles.contentContainer}>
<View style={styles.header}>
<Text style={styles.headerText}> List Header </Text>
</View>
<FlatList
data={Data}
keyExtractor={(item) => item.id.toString()}
renderItem={this.renderItem}
/>
</View>
)
}
};

const styles = StyleSheet.create({
header: {
height: 60,
backgroundColor: 'orange',
alignItems: 'center',
justifyContent: 'center',
},
headerText: {
fontSize: 20,
fontWeight: 'bold',
color: 'white',
},
contentContainer: {
backgroundColor: 'white',
},
item: {
flexDirection: 'row',
borderBottomWidth: 1,
borderBottomColor: 'grey',
alignItems: 'center',
},
marginLeft: {
marginLeft: 5,
},
menu: {
width: 20,
height: 2,
backgroundColor: '#111',
margin: 2,
borderRadius: 3,
},
text: {
marginVertical: 30,
fontSize: 20,
fontWeight: 'bold',
marginLeft: 10
, }
})

 

Jak edytować dane pojedynczej pozycji na liście?

Jeśli edytujemy dane na liście zadań, to zmiany te muszą zostać natychmiast na tej liście wyświetlone. W tym celu wykorzystamy stan komponentu, w którym zawarte będą dane wyświetlane we flatliscie i który będzie odświeżał nasz komponent za każdym razem, kiedy dane ulegną zmianie. Dlatego właśnie dane z pliku Data.js przeniesiemy do stanu komponentu List.js i stamtąd nasza lista będzie je odczytywać.

List.js:

 
export default class List extends Component {
constructor(props) {
super(props);
this.initData = Data
this.state = {
data: this.initData,
};
}
...

render() {
...
<FlatList
data={this.state.data}
...
/>
...
}

 

Chcielibyśmy, aby po kliknięciu na konkretne zadanie pojawiło się nowe okno, w którym będziemy mogli dokonać edycji treści. Dlatego do każdego elementu listy dodamy klikalny element, który spowoduje otwarcie takiego okna (przyda się nam tutaj komponent Modal – zobacz wpis: React Native modal example).

W komponencie Modal dodamy komponent TextInput, w którym wyświetlimy treść klikniętego zadania, którą będzie można zmienić. Po naciśnięciu przycisku Save nowa treść zostanie zapisana do stanu, który odświeży widok listy.

W tym celu musimy dokonać kilku zmian w naszym kodzie:

List.js:


import React, {Component} from 'react';
import {StyleSheet, Text, View, FlatList,  TextInput, Modal, TouchableHighlight  } from 'react-native';
import Data from './Data';

export default class List extends Component {
    constructor(props) {
        super(props);
        this.initData = Data
        this.state = {
            data: this.initData,
      isModalVisible: false,
            inputText: '',
            editedItem: 0, 
        };
    }

    setModalVisible = (bool) => {
        this.setState({ isModalVisible: bool })
    }

    setInputText = (text) => {
        this.setState({ inputText: text })
    }

    setEditedItem = (id) => {
        this.setState({ editedItem: id })
    }

    handleEditItem = (editedItem) => {
        const newData = this.state.data.map( item => {
            if (item.id === editedItem ) {
                item.text = this.state.inputText
                return item
            }
            return item
        })
        this.setState({ data: newData })
    }

    renderItem = ({item}) => (
        <TouchableHighlight onPress={() => {this.setModalVisible(true); this.setInputText(item.text), this.setEditedItem(item.id)}}
            underlayColor={'#f1f1f1'}> 
            <View style={styles.item} >
                <View style={styles.marginLeft}>
                    <View style={[styles.menu, { backgroundColor: item.color }]}></View>
                    <View style={[styles.menu, { backgroundColor: item.color }]}></View>
                    <View style={[styles.menu, { backgroundColor: item.color }]}></View>
                </View>
                <Text style={styles.text}> {item.text} </Text>
            </View>
        </TouchableHighlight>
    )
    
    render() {
        return (
            <View style={styles.contentContainer}>
                <View style={styles.header}>
                    <Text style={styles.headerText}> List Header </Text>
                </View>
                <FlatList 
                    data={this.state.data}
                    keyExtractor={(item) => item.id.toString()}
                    renderItem={this.renderItem}
                />
                <Modal animationType="fade" visible={this.state.isModalVisible} 
                    onRequestClose={() => this.setModalVisible(false)}>
                    <View style={styles.modalView}>
                        <Text style={styles.text}>Change text:</Text>
                        <TextInput
                            style={styles.textInput}
                            onChangeText={(text) => {this.setState({inputText: text}); console.log('state ', this.state.inputText)}}
                            defaultValue={this.state.inputText}
                            editable = {true}
                            multiline = {false}
                            maxLength = {200}
                        /> 
                        <TouchableHighlight onPress={() => {this.handleEditItem(this.state.editedItem); this.setModalVisible(false)}} 
                            style={[styles.touchableHighlight, {backgroundColor: 'orange'}]} underlayColor={'#f1f1f1'}>
                            <Text style={styles.text}>Save</Text>
                        </TouchableHighlight>  
                    </View>           
                </Modal> 
            </View>
        )
    }
};

const styles = StyleSheet.create({
    header: {
        height: 60,
        backgroundColor: 'orange',
        alignItems: 'center',
        justifyContent: 'center',
    },
    headerText: {
        fontSize: 20,
        fontWeight: 'bold',
        color: 'white',
    },
    contentContainer: {
        backgroundColor: 'white',
    },
    item: {
        flexDirection: 'row',
        borderBottomWidth: 1,
        borderBottomColor: 'grey',
        alignItems: 'center',
    },
    marginLeft: {
        marginLeft: 5,
    },
    menu: {
        width: 20,
        height: 2,
        backgroundColor: '#111',
        margin: 2,
        borderRadius: 3,
    },
    text: {
        marginVertical: 30,
        fontSize: 20,
        fontWeight: 'bold',
        marginLeft: 10,
    },

    textInput: {
        width: '90%',
        marginLeft: 10,
        marginRight: 10,
        marginBottom: 30,
        borderColor: 'gray', 
        borderBottomWidth: 2,
        fontSize: 16,
    },
    modalView: {
        flex: 1, 
        backgroundColor: 'white',
        alignItems: 'center',
        justifyContent: 'center',
    },
    touchableHighlight: {
        backgroundColor: 'white', 
        marginVertical: 10,
        alignSelf: 'stretch',
        alignItems: 'center',
    } 
})

Teraz lista stała się edytowalna, możemy zmienić treść każdego zadania:


No dobrze, ale dane zapisane do stanu znikają w momencie
odmontowania komponentu lub zamknięcia aplikacji, co więc możemy zrobić, aby aplikacja zapamiętała dane na stałe? Tego dowiesz się z kolejnego wpisu: Zapisywanie i odczytywanie danych z AsyncStorage

Joanna

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *