Redux应用抛出[Immer]错误,请求排查原因及解决方案
解决Redux Toolkit中Immer的"返回新值且修改draft"错误
错误原因
pushProduct函数里的Array.push()会直接修改原数组(数组是引用类型),同时你在reducer中又返回了新的状态对象{...state, ...},这违反了Immer的核心规则:要么修改draft状态,要么返回新的状态对象,不能同时执行两种操作。- 另外,
Array.push()的返回值是数组的新长度,而非新数组,这会导致product字段被设置成数字,而非预期的数组,属于隐藏bug。
解决方案
方案1:直接修改draft状态(Redux Toolkit推荐写法)
Redux Toolkit内置Immer,允许你直接修改state(实际操作的是Immer的draft副本),无需返回新对象。可以简化逻辑,直接在reducer中处理数组更新:
修改slice.js的reducer:
import { createSlice } from '@reduxjs/toolkit'; export const slice = createSlice({ name: 'initial', initialState : { product: [], }, reducers: { ADDS(state, actions) { console.log('State: ', state.product); console.log('Actions: ', actions.payload); // 直接修改draft的product数组,Immer自动处理不可变更新 state.product.push(actions.payload); // 无需返回任何值 } } }); export const { ADDS } = slice.actions; export default slice.reducer;
方案2:返回新状态对象(确保不修改原state)
如果坚持要返回新对象,必须保证pushProduct返回全新数组,不触碰原数组:
修正push.js:
// 返回新数组,不修改原数组 export const pushProduct = (initial, productSelect) => { return [...initial, productSelect]; // 也可以用concat实现:return initial.concat(productSelect); }
修改slice.js的reducer:
import { createSlice } from '@reduxjs/toolkit'; import { pushProduct } from '../commons/push'; export const slice = createSlice({ name: 'initial', initialState : { product: [], }, reducers: { ADDS(state, actions) { console.log('State: ', state.product); console.log('Actions: ', actions.payload); // 返回新对象,且pushProduct不会修改原state的product数组 return { ...state, product: pushProduct(state.product, actions.payload) }; } } }); export const { ADDS } = slice.actions; export default slice.reducer;
额外注意
不要在返回的状态对象中添加console1: console.log(...)这类字段,这会给state增加无意义的属性,控制台打印直接放在reducer逻辑里即可。
内容的提问来源于stack exchange,提问作者user17016241
相关产品推荐
相关产品推荐

