如何在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
相关产品推荐
相关产品推荐

