Angular 2+结合Redux使用Immer时无法修改嵌套对象quantity属性的报错求助
解决Immer无法修改嵌套类实例属性的只读错误
嘿,我来帮你搞定这个困扰你的Immer只读属性赋值错误!咱们先理清楚问题出在哪,再一步步解决。
问题根源
你碰到的TypeError: Cannot assign to read only property 'quantity' of object '[object Object]'主要有两个核心原因:
CartCarModel是类实例,Immer默认不兼容:Immer对普通JS对象/数组的可变更新支持很好,但类实例的属性可能因为类的封装特性,或者Redux的状态冻结机制,导致在Immer的draft对象里依然处于只读状态。- Reducer返回时的属性名写错了:你最后返回的是
{ drinks: nextState },但你的CartState定义的属性明明是cars,这会导致状态完全没更新,甚至可能引发其他奇怪问题。
具体解决方案
方案1:把类实例转为普通对象(推荐)
Immer最适配普通JavaScript对象,所以咱们可以调整状态的定义方式:
- 先把
CartCarModel改成接口(如果不需要类的方法,接口足够用):
export interface CartCar { carId: string; carModel: string; quantity: number; price: number; } export interface CartState { readonly cars: CartCar[] }
- 如果必须保留
CartCarModel类,在把实例加入状态时,用展开运算符转成普通对象:
// 比如添加购物车项时 const newCar = new CartCarModel('1', 'Model S', 1, 50000); // 转成普通对象再dispatch dispatch(addCar({ ...newCar }));
- 修正reducer的写法,去掉多余的
Object.assign:
function reducerFunc(state: CartState, id: string, quantity: number) { const nextState = produce(state, draft => { // 一定要加判断,避免找不到对应项时报错 const targetCar = draft.cars.find(d => d.carId === id); if (targetCar) { targetCar.quantity = quantity; } }); // Immer的produce已经返回了全新的状态对象,直接返回就行 return nextState; }
方案2:让Immer支持你的类实例
如果你确实需要保留CartCarModel类,可以给类加上Immer的标记,告诉它这个类是可以被可变处理的:
- 导入Immer的
immerable,并在类上添加静态属性:
import { immerable } from 'immer'; export class CartCarModel { // 标记这个类可以被Immer处理 [immerable] = true; constructor( public carId: string, public carModel: string, public quantity: number, public price: number ) { } }
- 同样修正reducer里的属性名错误,去掉多余的合并逻辑:
function reducerFunc(state: CartState, id: string, quantity: number) { const nextState = produce(state, draft => { const targetCar = draft.cars.find(d => d.carId === id); if (targetCar) { targetCar.quantity = quantity; } }); return nextState; }
额外提醒
- 永远要检查
find的结果是否存在,不然找不到对应车辆时会触发另一个错误:Cannot set property 'quantity' of undefined。 - Redux的状态是不可变的,Immer的作用就是让你用“写可变代码”的方式生成不可变状态,所以完全不需要再用
Object.assign去手动合并状态,produce已经帮你生成了全新的状态对象。
内容的提问来源于stack exchange,提问作者user15242670
相关产品推荐
相关产品推荐

