Redux状态数组读取更新异常,返回Proxy对象求助
Redux Toolkit Reducer 更新数组状态时出现已撤销Proxy对象
问题背景
预期状态数组格式:
[{productId: number; quantity: number}, ...]
需求:匹配对象的productId,若该对象已存在则更新quantity值,不存在则将整个对象添加到数组中。
首次添加元素正常,但后续更新数量或新增元素时,状态始终变成Proxy对象数组,Proxy结构如下:
Proxy{ [[Handler]]: null [[Target]]: null [[IsRevoked]]: true [[Prototype]]: Object }
尝试过的代码
最近的尝试:
const initialState: CartProduct[] = []; const updateCart = (state: CartProduct[], payload: CartProduct) => { const tempState = [...state, payload]; console.log({ tempState }); return tempState; export const countReducer = createSlice({ name: "cart", initialState, reducers: { increaseQuantity: (state, action) => { if (!state.length) { return updateCart(state, action.payload); } const index = state.findIndex( (item) => item.productId === action.payload.productId ); const newState = state; newState[index].quantity = newState[index].quantity + 1; console.log(newState); // 输出Proxy对象 }, }, });
此前的尝试:
increaseQuantity: (state, action) => { if (!state.length) { return updateCart(state, action.payload); } const newState = state.map((product) => { if (product.productId === action.payload.productId) { console.log("i increase count"); return { ...product, quantity: product.quantity + 1 }; } return product }); return updateCart(newState, action.payload); },
问题原因分析
- 直接修改原state引用:最近的代码中
const newState = state;只是复制了原状态的引用,后续修改newState[index].quantity属于直接篡改原状态,即使Redux Toolkit用Immer处理,这种写法也会引发状态异常。 - updateCart函数逻辑错误:该函数单纯将payload追加到数组末尾,完全忽略
productId是否已存在,会导致重复添加对象,同时返回新数组的方式与Immer的自动处理机制冲突,进而出现已撤销的Proxy。 - 错误的状态返回逻辑:createSlice的reducer中,若通过Immer修改draft state则无需返回新状态;若手动返回新状态,必须保证逻辑正确,否则会触发状态更新异常。
正确实现方案
利用Redux Toolkit内置的Immer,直接在draft state上完成修改,既简洁又符合规则,完美实现需求:
interface CartProduct { productId: number; quantity: number; } const initialState: CartProduct[] = []; export const countReducer = createSlice({ name: "cart", initialState, reducers: { increaseQuantity: (state, action) => { const targetProduct = state.find(item => item.productId === action.payload.productId); if (targetProduct) { // 存在则更新数量 targetProduct.quantity += 1; } else { // 不存在则添加新对象 state.push(action.payload); } }, }, }); // 导出action供组件调用 export const { increaseQuantity } = countReducer.actions;
关键说明
- Immer自动处理不可变性:createSlice会自动用Immer包装reducer,你可以直接修改state(实际是Immer的draft对象),无需手动解构或创建新数组,Immer会帮你生成合法的不可变新状态。
- 精准匹配需求:通过
find判断对象是否存在,存在则更新数量,不存在则添加新对象,完全符合业务逻辑。 - 避免Proxy异常:写法完全遵循Redux Toolkit的状态更新规则,Immer会正确处理draft对象,不会出现已撤销的Proxy问题。
手动不可变更新方案(可选)
如果不想依赖Immer的自动修改,也可以手动实现不可变更新:
increaseQuantity: (state, action) => { const hasProduct = state.some(item => item.productId === action.payload.productId); if (hasProduct) { return state.map(item => item.productId === action.payload.productId ? { ...item, quantity: item.quantity + 1 } : item ); } else { return [...state, action.payload]; } },
这种写法手动创建新数组和新对象,严格遵循不可变原则,同样能避免Proxy异常,但相比Immer写法更繁琐。
内容的提问来源于stack exchange,提问作者Afsheen Amroliwala
相关产品推荐
相关产品推荐

