You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:15:53