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

Redux修改数组对象字段报错:无法赋值给只读属性'liked'

解决Redux Store中对象数组单个字段修改的只读错误及最优方案

错误原因分析

你遇到的Cannot assign to read only property 'liked' of object '#<Object>'错误,核心问题有两个:

  1. 错误修改状态快照:在setListTreeItemLiked中使用current(state)获取的是Redux状态的不可变快照,直接修改快照内的对象会触发只读限制——Redux要求必须通过Immer提供的draft state进行修改,而非直接操作原始状态。
  2. setListTreeItems的payload处理错误:你的prepare函数将传入数据包装成了{data}结构,但reducer中直接对action.payload执行map,实际处理的是包装后的对象而非原始数组,导致状态结构异常。

最优修改方案(无性能损耗)

Redux Toolkit内置的Immer库已经提供了高效修改嵌套/数组状态的能力,无需手动克隆整个数组,只需直接修改draft state中目标元素的字段,Immer会自动生成最小化的新状态,避免不必要的内存开销。

修正后的Slice代码

import { createSlice } from '@reduxjs/toolkit';

export const sliceListTreeItems = createSlice({
  name: 'listTreeItems',
  initialState: { listTreeItems: [] },
  reducers: {
    // 修正列表初始化/更新逻辑
    setListTreeItems: (state, action) => {
      // 浅克隆数组内的每个对象,保证不可变性(若对象无嵌套,此操作足够)
      state.listTreeItems = action.payload.map(o => ({ ...o }));
    },
    // 高效修改单个元素的liked字段
    setListTreeItemLiked: (state, action) => {
      const { id, liked } = action.payload;
      // 使用find方法仅遍历到匹配元素即停止,比filter更高效
      const targetItem = state.listTreeItems.find(item => item.id === id);
      if (targetItem) {
        // 直接修改draft state中的字段,Immer自动处理不可变性
        targetItem.liked = liked;
      }
    }
  }
});

关键优化点说明

  • 避免全数组遍历:使用find替代filter,find会在找到第一个匹配元素后立即停止遍历,大幅降低大数据量下的性能开销。
  • 利用Immer自动处理不可变性:无需手动克隆整个数组或对象,直接修改draft state的目标字段即可,Immer会仅复制变化的部分生成新状态,内存占用极低。
  • 简化payload处理:移除不必要的prepare函数(若无需额外处理传入数据),直接将数组作为payload传入,减少逻辑复杂度。

补充说明

如果你的listTreeItem包含嵌套对象结构,需要修改深层字段时,可在找到目标元素后继续修改嵌套属性,Immer同样会自动处理不可变性,无需手动深克隆。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 06:10:39