繁体   English   中英

如何跟踪 Glimmer 组件中的嵌套属性?

[英]How to track a nested attribute in a Glimmer component?

我正在 Ember 中构建我的第一个 Glimmmer 组件,我的模板中有这样的东西:

<p>Some val: {{this.my_obj.some.deeply.nested.path.to.val}}</p>

然后我制作了一个相应的.js组件文件,并认为我会尝试从 HTML 中删除长路径。

我的第一次尝试是制作一个吸气剂:

get val() {
  return this.my_obj.some.deeply.nested.path.to.val;
}

现在使用模板:

<p>Some val: {{this.val}}</p>

这最初有效并显示分配给val变量的起始值,但它不会在基础val更改时更新。

所以我想我会尝试将 getter 标记为已跟踪,但这使输出消失了:

@tracked val;

get val() {
  return this.my_obj.some.deeply.nested.path.to.val;
}

然后我尝试了这个,但它不是有效的语法:

@tracked this.my_obj.some.deeply.nested.path.to.val;

那么这应该如何在 Glimmer 组件中处理呢?

当然,解决方案不是让 HTML 在每次引用变量时都引用这样的深层路径,但是新的 Ember 文档虽然很好,但在这个相对简单/常见的情况下,我没有更明智的选择。

很简单:无论您更改什么,都需要@tracked 如果您的hbs{{this.my_obj.some.deeply.nested.path.to.val}}或返回的 getter 没有任何区别。

但是如果你这样做this.my_obj.some.deeply.nested.path.to.val = "something"并且你想要更新值,你需要确保在this.my_obj.some.deeply.nested.path.to val定义为已跟踪。

所以这行不通:

@tracked data;
constructor() {
  super(...arguments);
  this.data = { foo: 1 };
}
@action test() {
  this.data.foo = 2; // this will not correctly update
}

您需要确保foo@tracked

class DataWrapper {
  @tracked foo;
}

...

@tracked data;
constructor() {
  super(...arguments);
  this.data = new DataWrapper();
  this.data.foo = 1;
}
@action test() {
  this.data.foo = 2; // this will now correctly update
}

或者你手动失效。 所以这将起作用:

@tracked data;
constructor() {
  super(...arguments);
  this.data = { foo: 1 };
}
@action test() {
  this.data.foo = 2; // this will not update
  this.data = this.data; // this ensures that everything that depends on `data` will correctly update. So `foo` will correctly update.
}

还有一件重要的事情: @tracked永远不应该在 getter 上定义。 这是行不通的。 它应该直接定义在您想要更改应该触发更新的内容的位置。 但是,您可以毫无问题地使用 getter。 只要您使用objsomething = value设置的所有内容都是正确的@tracked ,它就会@tracked 此外(纯)函数调用也能正常工作。

有一个附加组件。 https://www.npmjs.com/package/ember-tracked-nested适用于 Ember 3.16+。

基本上,它使用 DataWrapper 和缓存失效遵循 Lux 的回答。 相反,它是通过代理递归完成的,因此无论对象的结构或嵌套的方式如何,它都将始终有效。

import { tracked } from '@glimmer/tracking';
import Component from '@glimmer/component';
import { nested } from 'ember-tracked-nested';
import { action } from '@ember/object';

// works with POJO
export default class Foo extends Component {
  @tracked obj = nested({ bar: 2 });

  @action
  changeObj() {
      this.obj.bar = 10;
  }
}

// works when updating nested array
export default class Foo extends Component {
  @tracked obj = nested([{ bar: 2 }, { bar: 4 }]);
  
  @action
  changeObj() {
    this.obj[1].bar = 100;
  }
}

// works with array method
export default class Foo extends Component {
  @tracked obj = nested([{ bar: 2 }, { bar: 4 }]);

  @action
  changeObj() {
    this.obj.push({ bar: 6 });
  }
}

// works with POJO with getter
export default class Foo extends Component {
  @tracked obj = nested({ bar: 2, get foo() { return this.bar } });

  @action
  changeObj() {
    this.obj.bar = 9;
  }
}

我在这个备忘单中找到了答案 - https://ember-learn.github.io/ember-octane-vs-classic-cheat-sheet/#component-properties

有一个@computed装饰器,它可以正确跟踪嵌套属性的更改:

import { computed } from '@ember/object';

// Note that no 'this.' is used here
@computed("my_obj.some.deeply.nested.path.to.val")
get val() {
  return this.my_obj.some.deeply.nested.path.to.val;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM