[英]Why setState changes also the props which i added to the state before
[英]setState also changes screen props
我有一個大問題。 我有一個從另一個屏幕接收一些道具的屏幕,我通過<TicketDiaryHour {...this.props} />
將這些道具傳遞到那個屏幕中的組件中。 我在componentDidMount()方法中將組件中的這些道具設置為我的狀態。
在該組件 (TicketDiaryHour) 中,我也有 flatlist。 我的問題是我更改了 flatlist 中的數據(通過 setState)並且道具也在更改......我不知道為什么會發生這種情況。
我的 componentDidUpdate() 返回 prevProps == this.props 和 prevState == this.state。 我不知道為什么...
看:
Prev props: {"navigation":{"state":{"params":{"props":{"id":"418103","headingText":"Klavir","roomText":"Mala dvorana","student":"Ives Berlovčnik","apsent":"1/1","startTime":"07:00","endTime":"07:30","finished":"0","listOfStudents":[{"nameLastname":"Ives Berlovčnik","id":"43275","checked":false,"o":true,"n":false}],"minutes":"30","notes":"","lesson":""}}}
This props: {"navigation":{"state":{"params":{"props":{"id":"418103","headingText":"Klavir","roomText":"Mala dvorana","student":"Ives Berlovčnik","apsent":"1/1","startTime":"07:00","endTime":"07:30","finished":"0","listOfStudents":[{"nameLastname":"Ives Berlovčnik","id":"43275","checked":false,"o":true,"n":false}],"minutes":"30","notes":"","lesson":""}}}
組件代碼:Flatlist;
<FlatList
ref={(list) => this.myList = list}
style={[styles.flatList,{height: this.state.height}]}
data={this.state.data}
scrollEnabled = {this.state.showList ? true : false}
contentContainerStyle={{ padding: 15 }}
renderItem={({ item }) => (
<View style={styles.listItemStyle}>
<View style={{flexDirection: 'row', marginBottom: 7, }}>
{
item.checked &&
<TouchableOpacity
onPress={this.changeCheckedToFalse.bind(this,item)}>
<View style={styles.checked} />
</TouchableOpacity> ||
<TouchableOpacity
onPress={this.changeCheckedToTrue.bind(this,item)}>
<View style={styles.unchecked} />
</TouchableOpacity>
}
<Text style={{color: '#000', opacity: 0.6}}>{item.nameLastname}</Text>
{
item.checked &&
<View style={{position: 'absolute', right: 0 }}>
<View style={{flexDirection: 'row'}} >
{
item.o &&
<TouchableOpacity
style={[styles.touchable1Ch,styles.iconStyle1]}
onPress={this.changeSelectionO.bind(this,item)}>
<Text style={{color: '#fff', fontSize: 18, alignSelf: 'center' }}>O</Text>
</TouchableOpacity> ||
<TouchableOpacity
style={[styles.touchable1,styles.iconStyle1]}
onPress={this.changeSelectionO.bind(this,item)}>
<Text style={{color: '#fff', fontSize: 15, alignSelf: 'center' }}>O</Text>
</TouchableOpacity>
}
{
item.n &&
<TouchableOpacity
style={[styles.touchable2Ch,styles.iconStyle1]}
onPress={this.changeSelectionN.bind(this,item)}>
<Text style={{color: '#fff', fontSize: 18, alignSelf: 'center' }}>N</Text>
</TouchableOpacity> ||
<TouchableOpacity
style={[styles.touchable2,styles.iconStyle1]}
onPress={this.changeSelectionN.bind(this,item)}>
<Text style={{color: '#fff', fontSize: 15, alignSelf: 'center' }}>N</Text>
</TouchableOpacity>
}
</View>
</View>
}
</View>
{
this.props.navigation.state.params.props.listOfStudents !== undefined && this.props.navigation.state.params.props.listOfStudents.length >= 2 ?
<View style={styles.line} /> : <Text></Text>
}
</View>
)}
keyExtractor={item => item.id}
/>
我如何在該組件中加載數據:
componentDidMount() {
this.setState({
data: this.props.navigation.state.params.props.listOfStudents,
textOpombe: this.props.navigation.state.params.props.notes,
textVsebinaUre: this.props.navigation.state.params.props.lesson,
finished: this.props.navigation.state.params.props.finished,
absent: parseInt(this.props.navigation.state.params.props.apsent.substring(0,1)),
});
}
我如何更改 flatlist 中的數據;
changeCheckedToFalse = (item) => {
console.log('Item');
var arr = this.state.data;
var indexOfItem = arr.indexOf(item);
arr[indexOfItem].checked = false;
var abs = this.state.absent;
abs -= 1;
this.setState({
data: arr,
//scrollingParent: false,
//scrollingChild: true,
absent: abs,
});
console.log('State after changing: ' + JSON.stringify(this.state.data));
}
和最終代碼; 更改 flatlist 項時,會觸發此方法
componentDidUpdate(prevProps, prevState) {
console.log('Prev props: ' + JSON.stringify(prevProps));
console.log('This props: ' + JSON.stringify(this.props));
console.log('Prev state: ' + JSON.stringify(prevState));
}
在我看來,您實際上正在改變this.state.data
/ this.props.navigation.state.params.props.listOfStudents
- 因為它們是相同的。
我想你包括這一行: var arr = this.state.data;
試圖復制this.state.data
的值,但恐怕它不適用於引用類型(例如數組)。 arr
實際上指向完全相同的數組this.state.data
和this.state.data
點完全相同的數組this.props...listOfStudents
所以當你改變一個值時: arr[indexOfItem].checked = false;
你實際上是在改變道具。
React 非常重要的規則之一是“不要改變任何東西”,那么您將如何解決這個問題?
最簡單的方法是在更改數組之前正確復制它:
使用擴展運算符var arr = [...this.state.data];
或者Array.prototype.slice
方法var arr = this.state.data.slice()
編輯:雖然上述是正確的,並且如果您有一組原語可以解決您的問題,但實際上您有一組對象引用,這些問題與上述完全相同。
復制數組不會復制里面的對象,只是對這些對象的引用,所以你有同樣的問題。 嘗試對數組進行深拷貝:
var arr = this.state.data.map(x => ({...x}));
或者只復制您正在更改的對象:
var arr = [...this.state.data];
var indexOfItem = arr.indexOf(item);
arr[indexOfItem] = {...item, checked: false};
為什么說道具變了? 您在問題中指定的 prevProps 和 this.props 是相同的。 當您使用 setState 方法時,組件被更新,觸發 componentDidUpdate 生命周期方法運行。 這並不意味着你的道具改變了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.