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.

1 curtida

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}}

2 curtidas

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");
}
4 curtidas

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;
}
1 curtida

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

2 curtidas

Este tópico foi fechado automaticamente 30 dias após a última resposta. Novas respostas não são mais permitidas.