跟踪嵌套结构的问题

我正在 topic-above-footer-buttons 中插入一个 Glimmer 组件。此 Glimmer 组件尝试显示有关主题的一些元数据。我将这些序列化为 topic.my_metadata

当元数据从后台作业(!)更新时,主题会通过 MessageBus.publish(\"/topic/#{topic.id}\", { reload_topic: true, refresh_stream: true }) 刷新。

现在这可以在模板中正确更新:

{{this.args.topic.my_metadata.status}}

但是,当我通过 getter 访问它时:

get statusMessage() {
  return this.args.topic.my_metadata.status;
}

然后:

{{ this.statusMessage }}

不会更新。

(所有依赖于 this.args.topic.my_metadata 的 getter 也是如此。这才是真正的问题。)

我哪里做错了?

我已经尝试了很多方法,包括定义自定义事件、将 topic.my_metadata 复制到 @tracked metadata 然后使用 this.metadata 等等。

1 个赞

我认为,只有当一个 getter 所依赖的值被跟踪(并且该值发生更改)时,才能保证该 getter 会被重新计算。

因此,在这种情况下,我认为 {{this.args.topic.my_metadata.status}} 会更好,不过,你应该这样写:{{@topic.my_metadata.status}}

2 个赞

嗯,这不是“更好”与否的问题,JavaScript 中有大量的逻辑来评估元数据,例如决定是否显示某个按钮,就像这样:

get showButton() {
   // 对 this.args.topic.my_metadata.foo 和 this.args.topic.my_metadata.bar 进行一些繁重操作
}

所以我需要 getters,并且我需要它们以某种方式重新评估。

此外,Glimmer 文档说 *args 及其值会被自动跟踪。

如果模板能够自动跟踪它们,为什么 getter 不能?

甚至这样做也有效,将元数据作为参数传递

{{this.getStatus this.args.topic.my_metadata}}

使用

  getStatus(arg) {
    return arg.status;
  }

这是我们正在从 Ember 的“经典”响应式系统(get/set/computed)转换为“octane”@tracked / 原生 getter 的过程中不幸遇到的一个部分。

因此,正如上面讨论的,您示例中的问题在于您正在从原生 getter 访问非 @tracked 属性。

直接从模板访问完整路径将起作用,尽管正如您所说,它限制了可用的逻辑。

或者,使用 .get() 将允许 Ember 的新自动跟踪系统处理经典的(即非 @tracked)属性。

所以这种情况是:

get statusMessage() {
  return this.args.topic.get("my_metadata.status");
}
4 个赞

谢谢 David

您能否也使用 @computed 来解决这个问题,或者这是不可行的?

  @computed('args.topic.my_metadata.status')
  get statusMessage() {
    // this might be a lot more complicated
    return this.args.topic.my_metadata.status;
  }

我相信这可以缓存计算结果(如果计算量很大)。

(在这个例子中显然很简单,但这是 @RGJ 提到的)

@computed 是 Ember 经典响应式系统的一部分。它并未被正式弃用,但我们尽量避免在新代码中使用它。

如果你的 getter 足够复杂,需要缓存,那么你可以使用 @cached

import { cached } from "@glimmer/tracking";

...

@cached
get statusMessage() {
  // 这可能要复杂得多
  return this.args.topic.my_metadata.status;
}
1 个赞

这效果很好。谢谢你为我挽救了这个星期五的剩余时间,@david!!!非常感谢!!

2 个赞

此主题在上次回复后 30 天自动关闭。不再允许回复。