为什么你的 Redux Reducer 函数会意外修改原始数组?

12次阅读

为什么你的 Redux Reducer 函数会意外修改原始数组?

javascript对象引用类型,`reduce` 回调中直接修改 `case_data`(即原数组中对象的引用)会导致原始 `sourcearr` 被污染;正确做法是创建新对象而非就地修改。

在你提供的代码中,问题根源在于这行逻辑:

case_data.appointment = 'DD/MM/yyYY - hh:mm:ss A' case_data.name = 'Name'

虽然 case_data 是 reduce 的当前迭代项,但它并非独立副本,而是 sourceArr 中原始对象的直接引用。因此,对 case_data 属性的赋值操作,实质上是在修改 sourceArr 中对应对象本身——这违反了函数式编程中“不可变性”(immutability)的基本原则,也与 Redux 等状态管理理念背道而驰。

✅ 正确做法:返回全新对象,不触碰原数据

应使用对象展开语法({…case_data, …newProps})或 Object.assign() 创建浅拷贝,并覆盖指定字段:

let refined_data = newArr.reduce((acc, case_data) => {   // ✅ 安全:基于原对象创建新对象,不修改 sourceArr   return {     ...case_data,     appointment: 'DD/MM/YYYY - hh:mm:ss A',     name: 'Name'   }; }, {});

⚠️ 注意:{…case_data} 仅执行浅拷贝。若 case_data 内部含有嵌套对象(如 case_data.patient.address),仍需深度克隆(可借助 structuredClone() 或 Lodash 的 cloneDeep)。

? 额外优化建议

  • 避免轮询 window.sourceArr:setInterval + clearInterval 方式脆弱且低效。推荐改用 MutationObserver 监听全局变量注入,或由数据提供方主动触发事件(如 window.dispatchEvent(new CustomEvent(‘sourceReady’, { detail: data })))。
  • reduce 的初始值需匹配预期结构:你传入 {} 作为初始累加器,但 Filter 后的 newArr 可能为空数组(无匹配项),此时 reduce 不执行回调,直接返回 {} —— 这是合理的;但若期望始终返回单个对象,建议补充空值校验:
    const matched = sourceArr.find(data => data.case_id === current_case); const refined_data = matched    ? { ...matched, appointment: '...', name: '...' }    : null;

✅ 总结

错误行为 正确替代
case_data.name = ‘X’(直接赋值) return { …case_data, name: ‘X’ }(返回新对象)
依赖副作用修改输入 所有变换均通过纯函数返回新数据
忽略嵌套对象的可变性 深度克隆复杂嵌套结构(必要时)

遵循“永不直接修改输入对象”的原则,不仅能避免 sourceArr 被意外污染,更能提升代码可预测性、可测试性与协作友好度。

text=ZqhQzanResources