setState также меняет экранные реквизиты - PullRequest
0 голосов
/ 19 сентября 2018

У меня большая проблема.У меня есть экран, который получает некоторые реквизиты с другого экрана, я передаю эти реквизиты в компонент на этом экране через <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)),
        });
}

Как изменить данные в плоском списке;

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 голосов
/ 19 сентября 2018

Мне кажется, что вы на самом деле мутируете 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};
0 голосов
/ 19 сентября 2018

Почему вы говорите, реквизит изменился?PrevProps и this.props, которые вы указали в своем вопросе, совпадают.При использовании метода setState компонент обновляется, вызывая запуск метода жизненного цикла componentDidUpdate.Это не значит, что ваши реквизиты изменились.

...