You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux Toolkit存储数组复制后修改属性报错:为何需使用JSON.stringify和JSON.parse实现深拷贝?

为什么必须用JSON.stringify/JSON.parse才能修改Redux Toolkit中的数组元素?

这事儿核心原因在于两种复制方式的深浅差异,再加上Redux Toolkit(RTK)对状态的特殊处理,咱们一步步拆解:

1. 扩展运算符[...options]是浅拷贝,碰了RTK的只读代理

当你用[...options]复制数组时,你只是复制了数组本身的"外壳",但数组里的每个Options对象还是和RTK store里的原对象共用同一个引用。

而RTK为了强制保证状态的不可变性,会用Immer把store里的状态包装成只读的代理对象——这些对象的属性被冻结了,你直接修改它们的属性(比如copy[0].last = true),本质上还是在触碰原store里的只读对象,自然就会抛出"无法赋值给只读属性"的错误。

2. JSON.stringify/JSON.parse是深拷贝,彻底脱离原代理

JSON.parse(JSON.stringify(options))做了一次完整的深拷贝:它把整个数组和里面的所有对象都转换成无关联的JSON字符串,再重新解析成全新的JavaScript对象。这些新对象完全脱离了RTK store的代理包装,不再受只读限制,所以你可以自由修改它们的属性。

额外推荐:更符合RTK规范的写法

其实用JSON方法虽然能解决问题,但并不是最优解——它没法处理函数、Symbol这类JSON不支持的类型。RTK内置了Immer,你可以用更安全的方式处理状态:

  • 如果是在reducer里修改store状态:
const optionsSlice = createSlice({
  name: 'options',
  initialState: [] as Options[],
  reducers: {
    markFirstOptionAsLast: (state) => {
      // Immer允许你直接"修改",它会自动生成不可变的新状态
      if (state[0]) {
        state[0].last = true;
      }
    }
  }
});
  • 如果是在组件里生成临时修改的副本:
import { produce } from '@reduxjs/toolkit';

const modifiedOptions = produce(options, (draft) => {
  draft[0].last = true;
});

这种写法既安全,又符合RTK的设计逻辑。

内容的提问来源于stack exchange,提问作者Codehan25

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 17:07:25