Компонент не перерисовывается при изменении состояния Redux - PullRequest
0 голосов
/ 04 мая 2019

у меня RowsCont с renderRows

renderRows = () => {

    let result = [];

    const {rows} = this.props;
    console.log('RENDER');
    console.log(rows);
    for(let key in rows){
        result.push(<Row={rows[key].id} 
            onHover={this.onHover}
            row={rows[key]}/>);
        }
    return result;
};
....
render(){<div>{this.renderRows()}</div>}

....
function mapStateToProps(state) {
    console.log('mapState');
    console.log(state.rows.rows);
    return  {
        rows: state.rows.rows,
    }
}

Компонент строки:

    render(){

        return (
            <div>
                <div>{this.props.row.id}</div>
                <div>{this.props.row.value}</div>
            </div>
        )
    }

Строки - это набор объектов, каждый из которых выглядит так: {id: 5, value: 'some value'}

У меня есть редуктор, который изменяет значение объекта с определенным идентификатором:

case 'SET_NEW_ROW_VALUE':
        let currentRows = state.rows;
        const changedIndex = currentRows .findIndex((obj) => obj.id === action.id);

        currentRows [changedIndex].value = action.value;

        return Object.assign({}, state, {
            rows: currentRows 
});

Все работает, но если состояние изменяется, компонент не рендерится повторно. Я уверен, что это состояние изменилось, потому что я вижу новое состояние в mapStateToProps с console.log, каждый раз, когда оно изменяется, но я не вижу console.log из renderRows.

Каждый компонент строки имеет и onHover. Если я наведу курсор на строку, она будет перерисована, и я вижу новое состояние для строки с новым значением.

Ответы [ 2 ]

1 голос
/ 04 мая 2019

в редуксе вы должны никогда не изменять состояние , поэтому currentRows[changedIndex].value = action.value; запрещено

Вот возможное решение:

case 'SET_NEW_ROW_VALUE':
    const rows = state.rows.map(
      (row, index) => row.id !== action.id ? 
          row : 
          {...row, value: action.value}
    );

    return {...state, rows};

В вашем решении вынет новой ссылки для пропеллера state.rows после выполнения кейса SET_NEW_ROW_VALUE.Так как react-redux используйте shallow comparison (оператор ===), чтобы обнаружить, изменился ли объект, с вашим решением компонент не будет повторно визуализирован, так как state.rows будет тем же объектом (та же ссылка), что и до

1 голос
/ 04 мая 2019

Ваш компонент не рендерится, потому что ваш объект такой же, как был до

В цикле рендеринга React проверяет новые входящие реквизиты. Если что-то не так, оно будет перерисовано. В вашем случае объект - это тот же объект, что и раньше.

Как пример:

var rows = {id: 1, value: 'someVal'};
var oldRows = rows;
rows.id = 2;
rows.value = 'someNewVal';

console.log(rows === oldRows); // => true

React выполняет проверку различий между rows и oldRows и видит, что сам объект одинаков! Поскольку проверка различий видит равенство, повторного рендеринга не происходит.

Самый простой способ обойти это - обновить значения реквизитов их примитивами внутри объекта.

Например, это вызовет цикл перерисовки при изменении:

function mapStateToProps(state) {
    console.log('mapState');
    console.log(state.rows.rows);
    return  {
        id: state.rows.rows.id,
        value: state.rows.rows.value
    }
}

Если объект абсолютно необходим для передачи вашему компоненту, вы можете создать новый объект в своих хранилищах редуксов. Что-то вроде state.rows = Object.assign({}, oldRows) должно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...