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

NGXS集成报错:Cannot add property 0, object is not extensible

问题背景

该项目为待办清单类应用,支持创建按Sprint(迭代)分组的任务,同时可给任务指派负责人、设置负责人完成任务的预估工时。
接入NGXS状态管理时出现异常:在createTask方法中添加this.store.dispatch(new AddTask(task));代码行前应用运行正常,添加该行后,为任务指派负责人的changePersonAssigneInTask方法无法正常执行,浏览器控制台抛出如下错误:

ERROR TypeError: Cannot add property 0, object is not extensible
    at Array.push (<anonymous>)
    at DataBaseService.addPersonToTask (data-base.service.ts:78:20)
    at DataBaseService.changePersonAssigneInTask (data-base.service.ts:63:16)
    at DataService.changePersonAssigneInTask (data.service.ts:37:26)
    at TaskComponent.changePersonAssigneInTask (task.component.ts:68:22)
    at TaskComponent_div_20_Template_button_click_9_listener (task.component.html:49:28)
    at executeListenerWithErrorHandling (core.mjs:14979:1)
    at wrapListenerIn_markDirtyAndPreventDefault (core.mjs:15017:1)
    at HTMLButtonElement.<anonymous> (platform-browser.mjs:466:38)
    at _ZoneDelegate.invokeTask (zone.js:406:1)
相关代码

接口定义

export interface Sprint {
  personCapacities: PersonCapacity[];
  tasks: Task[];
  dates: Dates[];
  name: string;
}

export interface Task {
  number: string;
  name: string;
  assignees: Assignee[];
}

export interface Assignee {
  person: Person;
  hours: number;
}

任务创建逻辑

createTask() {
  const task: Task = {
    number: this.taskNumber,
    name: this.taskName,
    assignees: []
  };

  this.dataService.addTask(task, this.chosenSprint);
  this.store.dispatch(new AddTask(task));
}

dataService.addTask 实现

addTask(task: Task, chosenSprint: Sprint)
{
    this.sprints.find(value =>
      {
       if(value.name==chosenSprint.name)
        value.tasks.push(task)
      }
    )
}

任务指派负责人逻辑入口

changePersonAssigneInTask(person: Person, hours: number, task: Task) {
  this.dataService.changePersonAssigneInTask(person, hours, task);
}

dataService.changePersonAssigneInTask 实现

changePersonAssigneInTask(person: Person, hours: number, task: Task)
{
    let assignee = task.assignees.find(p => p.person.shortName == person.shortName);
    if ( assignee == null) {
        this.addPersonToTask(person, hours, task);
    } else {
        this.updatePersonHoursInTask(person, hours, task, assignee);
    }
}

dataService.addPersonToTask 实现(错误触发位置)

addPersonToTask(person: Person, hours: number, task: Task){
  task.assignees.push({ //<--该行抛出错误
    person,
    hours
  });
}

NGXS 相关代码

actions.ts

import {Task} from "../../models/task";

export class AddTask{
  static readonly type = '[TASK] Add Task';
  constructor(public task: Task) {
  }
}

state.ts

import {Action, Selector, State, StateContext} from '@ngxs/store';
import {AddTask} from '../actions/actions';
import {Task} from "../../models/task";
import {Injectable} from "@angular/core";
import {Role} from "../../models/person";

export interface TaskInterface {
  tasks: Task[];
}

@State<TaskInterface>({
  name: 't',
  defaults: {
    tasks: []
  }
})

@Injectable()
export class AddTaskAction{

  @Action(AddTask)
  AddTask(ctx: StateContext<TaskInterface>, action: AddTask){
    const {task} = action;
    const state = ctx.getState();

    if(!task)
      return;

    ctx.setState({
      ...state,
      tasks: [...state.tasks, task]
    });

    console.log(ctx.getState());
  }
}
问题原因

NGXS默认会在开发模式下对存入状态的所有对象做深度冻结,禁止外部代码直接修改状态,保证状态变更只能通过action触发。你在dispatch action时直接把原task对象的引用传入了状态,NGXS冻结这个对象后,它内部的assignees数组也会被冻结为不可扩展状态,后续直接调用task.assignees.push()修改原对象,就会抛出object is not extensible的错误。

修复方案

任选一种方案即可解决问题:

  • 传入NGXS状态时对对象做拷贝,避免原对象被冻结。dispatch时不要直接传原task的引用,传入拷贝后的新对象,这样NGXS冻结的是拷贝对象,不会影响业务流程中使用的原task对象。修改createTask方法中的dispatch代码:
    // 做嵌套浅拷贝,保证assignees数组是新的引用
    this.store.dispatch(new AddTask({
      ...task,
      assignees: [...task.assignees]
    }));
    
  • 遵循NGXS单向数据流规范,所有涉及任务修改的操作(包括添加负责人、更新工时)都通过派发action完成,在state的action handler里统一更新状态,不要在外部service直接修改被状态持有的对象引用。

内容的提问来源于stack exchange,提问作者Maikki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:51:24