Problema ao rastrear estrutura aninhada

Estou inserindo um componente Glimmer em topic-above-footer-buttons. Este componente Glimmer tenta mostrar alguns metadados sobre o tópico. Estou serializando-os para topic.my_metadata

Quando os metadados são atualizados de um job em segundo plano(!), o tópico é atualizado via MessageBus.publish(\"/topic/#{topic.id}\", { reload_topic: true, refresh_stream: true })

Agora isso atualiza corretamente no template:

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

No entanto, quando o acesso através de um getter

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

então

{{ this.statusMessage }}

não atualiza.

(E o mesmo vale para todos os getters que tenho e que dependem de this.args.topic.my_metadata de alguma forma. Que é o problema real).

O que estou fazendo de errado?

Já tentei muita coisa, incluindo definir eventos personalizados, copiar topic.my_metadata para um @tracked metadata e então usar this.metadata, etcetera.

Acho que você só tem a garantia de que um getter será reavaliado se um dos valores em que ele se baseia for rastreado (e isso mudar)

então, neste caso, acho que {{this.args.topic.my_metadata.status}} é melhor, embora, a propósito, você deva escrever assim: {{@topic.my_metadata.status}}

Bem, não se trata de ser “melhor” ou não, há muita lógica em Javascript avaliando os metadados e, por exemplo, decidindo se um botão deve ser exibido, como

get showButton() {
   // faz algumas coisas pesadas com this.args.topic.my_metadata.foo e this.args.topic.my_metadata.bar
}

então eu preciso dos getters e preciso que eles reavaliem de alguma forma.
Além disso, a documentação do Glimmer diz que args e seus valores são rastreados automaticamente.
Se o template é capaz de rastreá-los automaticamente, por que o getter não pode?
Até mesmo isso funciona, passando os metadados como um argumento

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

com

  getStatus(arg) {
    return arg.status;
  }

Esta é uma parte infeliz de estarmos no meio da conversão do sistema de reatividade ‘clássico’ do Ember (get/set/computed) para @tracked / getters nativos do ‘octane’.

Portanto, como discutido acima, o problema com seu exemplo é que você está acessando uma propriedade não @tracked de um getter nativo.

Acessar o caminho completo diretamente de um template funcionará, embora, como você diz, isso limite a lógica disponível.

Alternativamente, usar .get() permitirá que o novo sistema de autotracking do Ember funcione contra propriedades clássicas (ou seja, não @tracked).

Portanto, neste caso, seria

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

obrigado David

você também poderia resolver isso com @computed ou isso é um não-não?

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

Eu acredito que isso teria o benefício de armazenar em cache o resultado se o cálculo fosse significativo.

(obviamente trivial neste exemplo, mas algo que @RGJ aludiu)

@computed faz parte do sistema de reatividade clássico do Ember. Ele não é oficialmente descontinuado, mas tentamos evitar adicioná-lo a novos códigos.

Se o seu getter for complicado o suficiente para justificar o cache, você pode usar @cached:

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

...

@cached
get statusMessage() {
  // isso pode ser muito mais complicado
  return this.args.topic.my_metadata.status;
}

Isso funciona perfeitamente. Obrigado por salvar o resto da minha sexta-feira, @david!!! Muito apreciado!!