使用Redux-Toolkit时TypeScript类中数组的Reducer状态更新错误
解决Redux-Toolkit中Immer处理类实例数组的修改报错问题
问题原因
你遇到的「Cannot delete property '0' of [object Array]」错误,本质是Immer对类实例内部数组的代理机制导致的:
- 虽然你给ClassA加上了
[immerable] = true,让Immer能识别并代理类实例,但实例中的arrayA数组会被Immer转化为不可变代理对象。 - lodash的
pullAt底层用splice直接修改原数组,而Immer不允许直接修改不可变代理的结构,因此触发报错。 - 你测试的
pullAt([...this.arrayA], indexes)能运行,是因为复制后的数组不是Immer的代理,但这种方式只会修改副本,不会更新原状态的数组。
可行解决方案
方案1:修改ClassA的方法,用Immer处理数组更新
在removeIndexes方法内部,用Immer的produce来处理数组,确保修改的是Immer的可写draft,之后将新数组赋值回实例属性:
import { produce } from 'immer'; import { pullAt } from 'lodash'; class ClassA { [immerable] = true; arrayA: string[] = ["a", "b", "c"]; removeIndexes(indexes: number[]) { // 用produce创建可写的数组draft,修改后赋值回原属性 this.arrayA = produce(this.arrayA, (draftArray) => { pullAt(draftArray, indexes); }); } }
这样在reducer中调用classAInstance.removeIndexes(indexToRemove)时,Immer能正确追踪到arrayA的变化,同时保留原ClassA实例的其他属性。
方案2:在Reducer中直接通过Immer Draft修改数组
如果不想修改ClassA的方法,可以在reducer里直接操作draft实例的数组:
import { produce } from 'immer'; import { pullAt } from 'lodash'; // 在slice的reducer中 changeContentOfMap: (state, action) => { const { firstKey, secondKey, indexToRemove } = action.payload; const classAInstance = state.theMap[firstKey]?.[secondKey]; if (classAInstance) { // 直接对draft的arrayA进行produce处理 classAInstance.arrayA = produce(classAInstance.arrayA, (draft) => { pullAt(draft, indexToRemove); }); } }
这种方式不需要改动ClassA的内部逻辑,完全在reducer层面利用Immer的特性完成更新。
方案3:手动复制数组并赋值(无需Immer)
如果不想引入Immer的produce,也可以手动复制数组,修改后再赋值回实例,让Immer检测到属性变化:
import { pullAt } from 'lodash'; class ClassA { [immerable] = true; arrayA: string[] = ["a", "b", "c"]; removeIndexes(indexes: number[]) { const newArray = [...this.arrayA]; pullAt(newArray, indexes); // 必须将修改后的新数组赋值回原属性,Immer才能追踪变化 this.arrayA = newArray; } }
注意:必须把修改后的新数组赋值给this.arrayA,否则原状态不会更新(你之前测试的只修改副本的方式不会触发状态变化)。
为什么之前的produce包装无效?
你之前写的removeIndexesWithImmer方法,是在produce中调用原removeIndexes方法,而原方法还是直接修改Immer代理的数组,本质上还是在修改不可变结构,所以仍然报错。正确的做法是在produce内部直接操作数组,或者让方法内部通过produce生成新数组并赋值。
内容的提问来源于stack exchange,提问作者ThePainnn
相关产品推荐
相关产品推荐

