React 16.10组件传参异常:prevProps.xx与this.props.xx始终相同
解决React 16.10中componentDidUpdate props对比始终相同的问题
这个问题我之前也踩过坑,结合你的描述来看,大概率是引用类型数据的引用未更新导致的,我来拆解下原因和具体解决方案:
核心原因分析
你说父组件传参正确,但子组件componentDidUpdate里prevProps.xx和this.props.xx始终相同,首先要确认xx的数据类型:
- 如果是字符串、数字这类基本类型,那这个情况确实反常;但如果是对象、数组这类引用类型,几乎可以肯定是父组件更新
state时没有创建新的引用,导致传递给子组件的xx始终是同一个内存地址的对象/数组——React的props传递是值传递,但引用类型传递的是引用地址,所以prevProps.xx和this.props.xx指向同一个对象,用!=比较自然永远不成立。
比如父组件如果这么更新state(错误示例):
// 错误:直接修改原state对象,没有生成新引用 this.setState(prevState => { prevState.xx.someKey = 'newValue'; return prevState; });
这种写法直接篡改了原state对象,React的浅比较会认为state没有变化(或者即使触发重渲染,子组件拿到的还是同一个引用),导致子组件里的props对比失效。
具体解决方案
1. 父组件正确更新引用类型的state
更新对象或数组时,一定要创建新的引用,避免直接修改原state:
- 对于对象:使用扩展运算符生成新对象
// 正确写法 this.setState(prevState => ({ xx: { ...prevState.xx, // 拷贝原对象的所有属性 someKey: 'newValue' // 修改需要更新的属性 } }));
- 对于数组:使用扩展运算符或数组方法生成新数组
// 添加新元素 this.setState(prevState => ({ xx: [...prevState.xx, newItem] })); // 修改指定索引的元素 this.setState(prevState => ({ xx: prevState.xx.map((item, idx) => idx === targetIdx ? {...item, key: 'newVal'} : item) }));
2. 子组件中正确对比引用类型props
如果xx是引用类型,不要直接对比引用地址,而是对比具体的属性值:
componentDidUpdate(prevProps) { // 对比对象的具体属性 if (prevProps.xx?.someKey !== this.props.xx?.someKey) { // 执行你的业务逻辑 } // 对于数组,可以对比长度+具体元素(小型数组可用JSON.stringify,大型数组建议用更高效的深比较库) if (prevProps.xx?.length !== this.props.xx?.length || JSON.stringify(prevProps.xx) !== JSON.stringify(this.props.xx)) { // 执行逻辑 } }
3. 确认父组件是否触发了重渲染
可以在父组件的render方法里加个console.log('Parent component rendered'),如果父组件没有重渲染,那子组件自然不会收到新props。这种情况可能是父组件用了PureComponent或React.memo,而state更新没有通过浅比较导致的——这时候回到第一步,确保state更新时创建了新引用即可。
内容的提问来源于stack exchange,提问作者Levancho
相关产品推荐
相关产品推荐

