簡體   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