У меня есть приложение React / Redux, которое отображает сетку PureComponents. Я хочу, чтобы компоненты повторно отображались только при изменении значения реквизита, но на самом деле все компоненты повторно отображаются при любом обновлении для сохранения. Кажется, проблема вызвана свойством массива.
Я воспроизвел проблему в этой песочнице . В этом минимальном примере визуализируются два экземпляра компонента Cell. Каждый отображает значение, которое отдельно записывается в магазине, и может быть увеличено или уменьшено отдельно с помощью кнопки.
Ячейка. js
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { incrementAction, decreaseAction } from "./actions";
class Cell extends PureComponent {
render() {
const { index, value, incrementAction, decreaseAction } = this.props;
console.log("render cell with index", index);
return (
<div>
<h1>{value}</h1>
<button onClick={incrementAction}>increment</button>
<button onClick={decreaseAction}>decrease</button>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => ({
value: ownProps.index === 1 ? state.value1 : state.value2,
myArray: [0, 1, 2]
});
const mapDispatchToProps = (dispatch, ownProps) => ({
incrementAction: () => dispatch(incrementAction(ownProps.index)),
decreaseAction: () => dispatch(decreaseAction(ownProps.index))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(Cell);
Если вы проверите консоль, вы должен увидеть, что при нажатии одной кнопки обе ячейки будут повторно отображаться.
Если вы закомментируете реквизит myArray в mapStateToProps, поведение изменится так, что только ячейка, по которой вы щелкнули, выполнит повторную визуализацию.
Похоже, что PureComponent выполняет повторный рендеринг при любом изменении хранилища из-за свойства массива stati c.
В моем реальном приложении массив также поступил бы из хранилища, и Cell должен повторно выполнить рендеринг, если значение массива изменяется, но в примере с песочницей показано, как даже свойство массива stati c вызывает повторный рендеринг.
Есть ли какой-нибудь способ предоставить массив свойств для PureComponent и получить его перерисовывать только при смене реквизита? Спасибо.
Редактировать: я обновил песочницу , чтобы переместить myArray в хранилище, как предложено Domino987, и добавить функцию для вычисления подмассива, требуемого компонентом Cell - это то, что делает мое настоящее приложение. Я добавил памятку с повторным выбором и повторным выбором и сделал ее функциональным компонентом вместо PureComponent. Насколько я вижу, теперь это работает - только одна ячейка перерисовывается при нажатии кнопки. Ууу!
В действиях. js:
import createCachedSelector from "re-reselect";
export function getMyArray(state, index) {
console.log("getMyArrayCached for index", index);
return state.myArray;
}
export function getIndex(state, index) {
return index;
}
export const getMyArrayCached = createCachedSelector(
getMyArray,
getIndex,
(myArray, index) =>
myArray.map(elm => {
return elm[index - 1];
})
)((_state_, index) => index);
в редукторе. js:
const initialState = {
value1: 0,
value2: 0,
myArray: [[1, 2], [1, 2], [1, 2]]
};
в ячейке. js:
const mapStateToProps = (state, ownProps) => {
const value = ownProps.index === 1 ? state.value1 : state.value2;
return {
value,
myArray: getMyArrayCached(state, ownProps.index)
}};