React State变更追踪:修改Context状态时原始传入prop被同步改动如何解决
问题根因
- 引用类型直接修改导致原始prop被篡改
你传入的data、headings都是引用类型的数组,数组内部存储的是对象的内存引用:
- 在
onChangeCellContent方法中,你只对数组做了浅拷贝[...previousData],数组内的row对象仍然和原始prop里的row共享同一个引用,直接执行row[cellKey] = value会同时修改原始prop中的对象值 - 在
onChangeHeadingCell方法中,你甚至没有对headings数组做浅拷贝,遍历过程中直接修改原heading对象的属性,同样会篡改原始prop
- 状态同步逻辑缺陷
你写的useEffect只判断了data的长度是否变化,当外部传入的data数组长度不变、但内部元素内容更新时,不会触发内部tableData的同步更新 - useTable判断逻辑错误
判断context不存在的条件写的是context === "undefined",这是匹配字符串的逻辑,永远不会触发错误抛出,应该直接判断context === undefined
修复方案
1. 修改状态更新逻辑,避免直接修改原引用
更新对象属性时,要对被修改的对象也做一次拷贝,不要直接修改原引用指向的对象:
// 修改onChangeHeadingCell const onChangeHeadingCell = ({ key, value }) => { setHeadings((oldHeadings) => oldHeadings.map((heading) => { // 匹配到的对象做浅拷贝,再修改新对象的属性 if (heading.key === key) { return { ...heading, title: value }; } return heading; }) ); }; // 修改onChangeCellContent const onChangeCellContent = ({ rowId, cellKey, value }) => { setData((previousData) => previousData.map((row) => { if (row.id === rowId) { // 行对象做浅拷贝,再修改新对象的属性 return { ...row, [cellKey]: value }; } return row; }) ); };
2. 调整useEffect同步逻辑
如果需要同步外部传入的data更新,可以直接序列化data做值比较,避免只判断长度的问题:
useEffect(() => { setData(data); }, [JSON.stringify(data)]); // 如果项目里有深比较工具,也可以用深比较依赖,性能更好
3. 修复useTable的错误判断
export const useTable = () => { const context = useContext(TableContext); if (context === undefined) { throw Error("Table provider missing"); } return context; };
4. 可选优化:初始化state时做一次浅拷贝
避免初始化时直接复用外部prop的引用,减少误改风险:
const [tableData, setData] = useState([...data]); const [tableHeadings, setHeadings] = useState([...headings]);
内容的提问来源于stack exchange,提问作者Merim
相关产品推荐
相关产品推荐

