Redux修改数组对象字段报错:无法赋值给只读属性'liked'
解决Redux Store中对象数组单个字段修改的只读错误及最优方案
错误原因分析
你遇到的Cannot assign to read only property 'liked' of object '#<Object>'错误,核心问题有两个:
- 错误修改状态快照:在
setListTreeItemLiked中使用current(state)获取的是Redux状态的不可变快照,直接修改快照内的对象会触发只读限制——Redux要求必须通过Immer提供的draft state进行修改,而非直接操作原始状态。 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
相关产品推荐
相关产品推荐

