Problema para seguir estructuras anidadas

Estoy insertando un componente Glimmer en topic-above-footer-buttons. Este componente Glimmer intenta mostrar algunos metadatos sobre el tema. Estoy serializando esto a topic.my_metadata

Cuando los metadatos se actualizan desde un trabajo en segundo plano (!), el tema se actualiza a través de MessageBus.publish(\"/topic/#{topic.id}\", { reload_topic: true, refresh_stream: true })

Ahora esto se actualiza correctamente en la plantilla:

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

Sin embargo, cuando accedo a él a través de un getter

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

entonces

{{ this.statusMessage }}

no se actualiza.

(Y lo mismo ocurre con todos los getters que tengo y que dependen de this.args.topic.my_metadata de alguna manera. Que es el problema real).

¿Qué estoy haciendo mal?

Ya he intentado mucho, incluyendo definir eventos personalizados, copiar topic.my_metadata a un @tracked metadata y luego usar this.metadata, etc.

1 me gusta

Creo que solo se garantiza que un getter se reevaluará si uno de los valores en los que se basa está rastreado (y ese cambia)

así que en este caso creo que {{this.args.topic.my_metadata.status}} es mejor, aunque por cierto deberías escribirlo así: {{@topic.my_metadata.status}}

2 Me gusta

Bueno, no es una cuestión de “mejor” o no, hay mucha lógica en Javascript evaluando los metadatos y, por ejemplo, decidiendo si se debe mostrar un botón, como

get showButton() {
   // haz algunas cosas pesadas con this.args.topic.my_metadata.foo y this.args.topic.my_metadata.bar
}

así que necesito los getters y necesito que se reevalúen de alguna manera.

Además, la documentación de Glimmer dice que args y sus valores se rastrean automáticamente.

Si la plantilla puede rastrearlos automáticamente, ¿por qué no puede el getter?

Incluso esto funciona, pasando los metadatos como argumento

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

con

  getStatus(arg) {
    return arg.status;
  }

Esta es una parte desafortunada de que estemos a mitad de camino en la conversión del sistema de reactividad ‘clásico’ de Ember (get/set/computed) a @tracked / native-getters de ‘octane’.

Así que, como se discutió anteriormente, el problema con tu ejemplo es que estás accediendo a una propiedad no @tracked desde un native getter.

Acceder a la ruta completa directamente desde una plantilla funcionará, aunque como dices, limita la lógica disponible.

Alternativamente, usar .get() permitirá que el nuevo sistema de autotracking de Ember funcione contra propiedades clásicas (es decir, no @tracked).

Así que en este caso, sería

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

gracias David

¿podrías resolver esto también con @computed o eso es un no-no?

  @computed('args.topic.my_metadata.status')
  get statusMessage() {
    // esto podría ser mucho más complicado
    return this.args.topic.my_metadata.status;
  }

Creo que esto tendría el beneficio de almacenar en caché el resultado si el cálculo fuera significativo.

(obviamente trivial en este ejemplo, pero algo a lo que @RGJ aludió)

@computed es parte del sistema de reactividad clásico de Ember. No está oficialmente obsoleto, pero intentamos evitar agregarlo a código nuevo.

Si tu getter es lo suficientemente complicado como para justificar el almacenamiento en caché, puedes usar @cached:

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

...

@cached
get statusMessage() {
  // esto podría ser mucho más complicado
  return this.args.topic.my_metadata.status;
}
1 me gusta

Esto funciona a la perfección. ¡Gracias por salvar el resto de mi viernes @david! ¡Muy apreciado!

2 Me gusta

Este tema se cerró automáticamente 30 días después de la última respuesta. Ya no se permiten nuevas respuestas.