Reduce回调错误修改数组:为何dataMonth状态被意外修改?
问题原因及解决方案
核心原因:浅拷贝导致引用共享
你用{...dataMonth}做的是浅拷贝——它只会复制对象的第一层属性,对于嵌套的子对象(比如dataMonth.datasets里的每个元素),拷贝的是它们的内存引用,而不是创建全新的独立对象。所以你修改dataYear.datasets里的value.data时,其实是在修改和dataMonth.datasets共享的同一个对象,自然会连带修改dataMonth。
代码问题拆解
dataYear = { ...dataMonth }:仅复制了dataMonth的顶层属性(如labels、datasets),但datasets数组里的每个元素还是和原dataMonth里的元素指向同一块内存。- 后续
forEach中修改value.data时,value是原dataMonth.datasets元素的引用,操作会直接同步到dataMonth上。
解决办法:改用深拷贝
需要完全复制嵌套的所有对象,切断引用关联,常用两种方式:
方式1:用JSON序列化(适合无特殊类型的场景)
如果dataMonth里没有函数、Symbol、循环引用这类JSON无法序列化的内容,这种方式最简单:
dataYear = JSON.parse(JSON.stringify(dataMonth));
方式2:手动递归深拷贝(适合复杂场景)
如果有特殊类型,可自己写递归拷贝逻辑,比如:
function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (obj instanceof Array) return obj.map(item => deepClone(item)); const clonedObj = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = deepClone(obj[key]); } } return clonedObj; } // 使用 dataYear = deepClone(dataMonth);
修正后的完整代码
另外注意原代码里reduce的写法有问题(没传初始值,且直接在回调里修改value.data),一起修正:
const [dataMonth, setDataMonth] = useState(null); let dataYear = {}; useEffect(() => { if (dataMonth !== null) { // 深拷贝切断引用 dataYear = JSON.parse(JSON.stringify(dataMonth)); dataYear.labels = ["Année " + year]; dataYear.datasets.forEach((value) => { // 正确求和,传入初始值0避免空数组报错 const total = value.data.reduce((prev, val) => prev + val, 0); value.data = [total]; }); } }, [dataMonth, year]); // year作为依赖要加入数组
内容的提问来源于stack exchange,提问作者Hello World
相关产品推荐
相关产品推荐

