[英]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.