我有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'}
我有reducer,它可以更改具有特定ID的对象的值:
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
中的新状态,但是看不到{{1}中的console.log
}。
每个行组件都具有和renderRows
。如果我将鼠标悬停在该行上,则会重新渲染该行,并看到具有新值的行的新状态。
答案 0 :(得分:1)
您的组件未重新呈现,因为您的对象与以前相同
在渲染周期中,React对新传入的道具进行差异检查。如果有任何不同,它将重新渲染。在您的情况下,该对象与以前的对象相同。
例如:
var rows = {id: 1, value: 'someVal'};
var oldRows = rows;
rows.id = 2;
rows.value = 'someNewVal';
console.log(rows === oldRows); // => true
React在rows
和oldRows
之间进行差异检查,发现对象本身是相同的!由于diff检查发现相等,因此不会发生任何重新渲染。
解决此问题的最简单方法是在对象内通过属性值更新属性值。
例如,当发生更改时,这将强制重新渲染周期:
function mapStateToProps(state) {
console.log('mapState');
console.log(state.rows.rows);
return {
id: state.rows.rows.id,
value: state.rows.rows.value
}
}
如果绝对需要将对象传递给组件,则可以在redux存储中创建一个新对象。像state.rows = Object.assign({}, oldRows)
之类的方法就可以解决问题。
答案 1 :(得分:1)
在还原中,您应该从不更改状态,因此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
将是同一对象(参考相同)