ComponentDidUpdate中prevState与this.state始终相等问题排查
状态更新后ComponentDidUpdate中prevState与currState始终相等的问题
问题代码与现象
更新状态的函数:
doChangeValue(data) { const dataNew = this.state.data dataNew[data.id] = data.value this.setState({ ...dataNew, [dataNew[data.id]]: data.value}) }
最初的突变写法:
const dataNew = this.state.data dataNew[data.id] = data.value this.setState({ data: dataNew })
ComponentDidUpdate代码:
componentDidUpdate(prevProps, prevState) { const prev = prevState.data const curr = this.state.data const isStateChanged = isEqual(prev, curr) console.log(isStateChanged); }
现象:即便状态已改变,isStateChanged始终返回true,prev和curr始终相等。
错误原因
- 仍在直接突变原state对象:
const dataNew = this.state.data只是把原state中data对象的引用赋值给了dataNew,并没有创建新对象。后续dataNew[data.id] = data.value直接修改了原state里的data,导致prevState.data和currState.data指向同一个对象,引用完全相同。 - setState的写法错误:你在
setState中展开了dataNew的所有属性到state根节点,还重复添加了[dataNew[data.id]]: data.value,这完全偏离了原本要更新state.data的目标,同时因为原data对象已经被突变,即使执行了setState,新旧state中的data引用还是同一个。
修正方案
要彻底避免突变,必须先创建原data对象的浅拷贝,修改拷贝后的对象,再通过setState更新state.data字段:
方案1:使用扩展运算符创建拷贝
doChangeValue(data) { // 创建原data的浅拷贝,生成新对象 const dataNew = { ...this.state.data }; // 修改新对象的属性 dataNew[data.id] = data.value; // 更新state中的data字段 this.setState({ data: dataNew }); }
方案2:使用Object.assign创建拷贝
doChangeValue(data) { const dataNew = Object.assign({}, this.state.data); dataNew[data.id] = data.value; this.setState({ data: dataNew }); }
这样修改后,新的dataNew是完全独立的新对象,setState会更新state.data为这个新对象。此时在componentDidUpdate中,prevState.data是旧对象引用,currState.data是新对象引用,isEqual就能正确判断两者是否相等。
内容的提问来源于stack exchange,提问作者semen_nova
相关产品推荐
相关产品推荐

