You need to enable JavaScript to run this app. 如何在Ember.js中更新@tracked数组内对象值以实现页面响应式更新
优惠活动
大模型
产品
解决方案
定价
更多

如何在Ember.js中更新@tracked数组内对象值以实现页面响应式更新

问题原因

@tracked 装饰器对复杂类型(数组、对象)默认做的是引用跟踪,只有当被装饰变量的内存引用真正发生变化时,才会触发重新渲染。你当前的写法存在两个问题:

  • 直接修改数组内部对象的属性,没有改变state数组本身的引用
  • 执行this.state = this.state属于自赋值,数组引用没有变化,所以跟踪逻辑不会触发更新
解决方案

三种实现方式可根据业务场景选择:

方案1:替换整个数组(最简便,适合低频修改场景)

修改对象属性后,创建一个新的数组副本赋值给state,触发引用变更:

@action
updateData(val) {
  // 先修改目标属性
  this.state[0].two = val;
  // 用扩展运算符创建新数组,替换原引用
  this.state = [...this.state];
}

方案2:深度跟踪嵌套属性(适合频繁修改嵌套属性的场景)

如果经常需要修改数组内对象的属性,可以用TrackedObject、TrackedArray(来自@ember/tracking包)包装数据,修改内部属性即可直接触发更新:

import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from "@ember/object";
import { TrackedArray, TrackedObject } from '@ember/tracking';

export default class TictactoeDataService extends Service {
  // 初始化的时候用Tracked包装类包裹嵌套数据
  @tracked state = TrackedArray.from([
    TrackedObject.create({ "one": "1", "two": "", "three": "" }),
    TrackedObject.create({ "one": "2", "two": "", "three": "" }),
    TrackedObject.create({ "one": "3", "two": "", "three": "" })
  ])
  get all() {
    return this.state
  }
  @action
  updateData(val) {
    // 直接修改属性即可触发更新
    this.state[0].two = val;
  }
}

方案3:拷贝修改目标对象再更新数组

如果不想引入额外的Tracked包装类,也可以单独拷贝要修改的对象,再生成新数组赋值:

@action
updateData(val) {
  // 拷贝第一个对象,更新属性
  const updatedFirstItem = {
    ...this.state[0],
    two: val
  };
  // 生成新数组,替换对应位置的对象
  this.state = [
    updatedFirstItem,
    ...this.state.slice(1)
  ]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 09:45:03