setState还会更改屏幕道具

时间:2018-09-19 08:54:05

标签: javascript reactjs react-native react-props

我有一个大问题。我有一个屏幕,它从另一个屏幕接收一些道具,我通过<TicketDiaryHour {...this.props} />将这些道具传递到该屏幕的组件中。我在 componentDidMount()方法中将元件中的道具设置为我的状态。

在该组件(TicketDiaryHour)中,我也有一个列表。我的问题是我更改了平面列表中的数据(通过setState),而props也正在更改...我不知道为什么会这样。

我的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
                                    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)),
        });
}

如何更改单位列表中的数据;

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));
    }

最后的代码;更改清单列表项时,将触发此方法

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));
}

2 个答案:

答案 0 :(得分:1)

在我看来,您实际上是在突变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()

编辑:尽管上面的描述是正确的,并且如果您有一组原语可以解决您的问题,但实际上您有一组对象引用,这些对象引用与上述问题完全相同。< / p>

复制数组不会复制内部对象,而只会复制对这些对象的引用,因此您会遇到相同的问题。尝试对数组进行深层复制:

var arr = this.state.data.map(x => ({...x}));

或者仅复制您要更改的对象:

var arr = [...this.state.data];
var indexOfItem = arr.indexOf(item);

arr[indexOfItem] = {...item, checked: false};

答案 1 :(得分:0)

您为什么说道具变了?您在问题中指定的prevProps和this.props相同。使用setState方法时,将更新组件,从而触发componentDidUpdate生命周期方法运行。这并不意味着您的道具已经改变。