React双useReducer实例数据还原仅首次生效问题排查
问题诱因
核心原因是JS引用类型浅拷贝共享内存地址导致的备份数据被意外污染:
FETCH_SUCCESS阶段你给两个reducer赋值的是同一个payload数组引用,reducer1的data和reducer2的val本质指向内存中的同一个数组对象- 后续修改reducer1的
data时,因为直接修改了引用指向的数组内容,共享同一引用的reducer2的val也会同步变更 - 还原时写的
{...alertOriLogsContext.lineOriDetailsState}仅对state外层对象做了浅拷贝,内部的val数组依然和reducer1的data共享引用,第一次还原后后续修改操作还是会污染备份数据。
修复方案
1. 存储备份时切断引用关联
给备份reducer(reducer2)赋值时,先对payload做深拷贝,从根源上避免和可变数据共享引用。如果是普通JSON结构可以直接用JSON序列化反序列化实现深拷贝,复杂结构可以用自定义深拷贝逻辑或者lodash的cloneDeep。
修改reducer2的FETCH_SUCCESS分支:
case "FETCH_SUCCESS": return { ...lineOriDetailsState, // 深拷贝后再存入备份 val: JSON.parse(JSON.stringify(action.payload)) };
2. 还原时二次深拷贝避免反向污染
给reducer1赋值备份数据时,再次对备份值做深拷贝,避免后续修改reducer1的数据反向污染备份存储:
修改还原按钮逻辑:
// 深拷贝备份值后再传给可变数据reducer const restoredData = JSON.parse(JSON.stringify(alertOriLogsContext.lineOriDetailsState.val)) alertLogsContext.lineDetailsDispatch({ type: "update", payload: restoredData });
3. 优化可变数据的更新逻辑
修改reducer1的更新逻辑时严格遵循React不可变更新原则,每次修改都返回新的数组/对象引用,不要直接修改原state的内容,降低意外污染风险:
case "update": // 先拷贝生成新数组,修改新数组后再返回 const newData = [...lineDetailsState.data]; // 对newData做修改操作,如果数组项是对象,也要单独对修改的对象做深拷贝 return { ...lineDetailsState, data: newData };
注意:如果你的数据包含
undefined、Symbol、函数、循环引用等特殊结构,JSON.parse(JSON.stringify())会丢失内容,这种场景建议使用自定义深拷贝方法或者lodash的cloneDeep方法。
内容的提问来源于stack exchange,提问作者Deepika Rao
相关产品推荐
相关产品推荐

