Я вставляю компонент Glimmer в topic-above-footer-buttons. Этот компонент Glimmer пытается отобразить некоторые метаданные о теме. Я сериализую их в topic.my_metadata.
Когда метаданные обновляются из фоновой задачи (!), тема обновляется через MessageBus.publish("/topic/#{topic.id}", { reload_topic: true, refresh_stream: true }).
Теперь это правильно обновляется в шаблоне:
{{this.args.topic.my_metadata.status}}
Однако, когда я обращаюсь к нему через геттер
get statusMessage() {
return this.args.topic.my_metadata.status;
}
то
{{ this.statusMessage }}
не обновляется.
(То же самое относится ко всем геттерам, которые я использую и которые так или иначе зависят от this.args.topic.my_metadata. Это и есть реальная проблема).
Что я делаю не так?
Я уже перепробовал многое, включая определение пользовательских событий, копирование topic.my_metadata в @tracked metadata и последующее использование this.metadata и так далее.
Я считаю, что гарантированная повторная оценка геттера происходит только в том случае, если отслеживается одно из зависимых значений (и оно изменяется).
Поэтому в данном случае, думаю, лучше использовать {{this.args.topic.my_metadata.status}}, хотя, кстати, писать это следует так: {{@topic.my_metadata.status}}.
Что ж, дело не в том, «лучше» это или нет. В JavaScript есть логика оценки метаданных, например, для решения о том, следует ли отображать кнопку, как в этом примере:
get showButton() {
// выполняем тяжелые операции с this.args.topic.my_metadata.foo и this.args.topic.my_metadata.bar
}
Поэтому мне нужны геттеры, и мне нужно, чтобы они как-то переоценивались.
Кроме того, в документации по Glimmer сказано, что args и их значения отслеживаются автоматически.
Если шаблон может автоматически отслеживать их, почему геттер не может?
Даже это работает — передача метаданных в качестве аргумента:
Это неприятная особенность нашего перехода от классической системы реактивности Ember (get/set/computed) к системе Octane с использованием @tracked и нативных геттеров.
Как обсуждалось выше, проблема в вашем примере заключается в том, что вы обращаетесь к свойству, не помеченному как @tracked, из нативного геттера.
Прямой доступ к полному пути из шаблона будет работать, хотя, как вы верно заметили, это ограничивает доступную логику.
В качестве альтернативы использование .get() позволит новой системе автотрекинга Ember работать с классическими (то есть не помеченными как @tracked) свойствами.
Таким образом, в данном случае код будет выглядеть так:
get statusMessage() {
return this.args.topic.get("my_metadata.status");
}
Ты мог бы также решить это с помощью @computed, или это плохая идея?
@computed('args.topic.my_metadata.status')
get statusMessage() {
// здесь логика может быть гораздо сложнее
return this.args.topic.my_metadata.status;
}
Полагаю, это дало бы преимущество кэширования результата, если вычисления значительны.
(очевидно, тривиально в этом примере, но то, на что намекал @RGJ)
@computed является частью классической системы реактивности Ember. Она официально не устарела, но мы стараемся избегать её использования в новом коде.
Если ваш геттер достаточно сложен для кэширования, вы можете использовать @cached:
import { cached } from "@glimmer/tracking";
...
@cached
get statusMessage() {
// это может быть гораздо сложнее
return this.args.topic.my_metadata.status;
}