Spis treści
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:
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