Problème de suivi de structure imbriquée

J’insère un composant Glimmer dans topic-above-footer-buttons. Ce composant Glimmer tente d’afficher des métadonnées sur le sujet. Je les sérialise dans topic.my_metadata

Lorsque les métadonnées sont mises à jour à partir d’un job en arrière-plan (!), le sujet est actualisé via MessageBus.publish(\"/topic/#{topic.id}\", { reload_topic: true, refresh_stream: true })

Maintenant, cela se met correctement à jour dans le template :
{{this.args.topic.my_metadata.status}}

Cependant, lorsque j’y accède via un getter

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

alors
{{ this.statusMessage }}
ne se met pas à jour.

(Et il en va de même pour tous les getters que j’ai et qui dépendent de this.args.topic.my_metadata d’une manière ou d’une autre. Ce qui est le vrai problème).

Qu’est-ce que je fais mal ?

J’ai déjà essayé beaucoup de choses, y compris définir des événements personnalisés, copier topic.my_metadata dans un @tracked metadata puis utiliser this.metadata, etcetera.

1 « J'aime »

Je pense que vous n’êtes garanti qu’un getter sera réévalué que si l’une des valeurs sur lesquelles il repose est suivie (et que cela change)

donc dans ce cas, je pense que {{this.args.topic.my_metadata.status}} est mieux, bien qu’au fait, vous devriez l’écrire comme ceci : {{@topic.my_metadata.status}}

2 « J'aime »

Eh bien, il ne s’agit pas de savoir si c’est « mieux » ou non, il y a beaucoup de logique en Javascript qui évalue les métadonnées et, par exemple, décide si un bouton doit être affiché, comme

get showButton() {
   // fait des choses lourdes sur this.args.topic.my_metadata.foo et this.args.topic.my_metadata.bar
}

donc j’ai besoin des getters et j’ai besoin qu’ils se réévaluent d’une manière ou d’une autre.

De plus, la documentation Glimmer indique que args et ses valeurs sont automatiquement suivis.

Si le template est capable de les suivre automatiquement, pourquoi pas le getter ?

Même ceci fonctionne, en passant les métadonnées comme argument

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

avec

  getStatus(arg) {
    return arg.status;
  }

C’est un aspect malheureux du fait que nous soyons en pleine conversion du système de réactivité « classic » d’Ember (get/set/computed) vers le système « octane » @tracked / getters natifs.

Ainsi, comme discuté ci-dessus, le problème avec votre exemple est que vous accédez à une propriété non-@tracked à partir d’un getter natif.

Accéder au chemin complet directement depuis un template fonctionnera, bien que, comme vous le dites, cela limite la logique disponible.

Alternativement, l’utilisation de .get() permettra au nouveau système d’autotracking d’Ember de fonctionner avec les propriétés classiques (c’est-à-dire non-@tracked).

Donc, dans ce cas, ce serait

get statusMessage() {
  return this.args.topic.get("my_metadata.status");
}
4 « J'aime »

Merci David

Pourriez-vous également résoudre ceci avec @computed ou est-ce à proscrire ?

  @computed('args.topic.my_metadata.status')
  get statusMessage() {
    // cela pourrait être beaucoup plus compliqué
    return this.args.topic.my_metadata.status;
  }

Je pense que cela aurait l’avantage de mettre en cache le résultat si le calcul était important.

(évidemment trivial dans cet exemple mais quelque chose que @RGJ a fait allusion)

@computed fait partie du système de réactivité classique d’Ember. Il n’est pas officiellement déprécié, mais nous essayons d’éviter de l’ajouter au nouveau code.

Si votre getter est suffisamment complexe pour justifier la mise en cache, vous pouvez utiliser @cached :

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

...

@cached
get statusMessage() {
  // cela pourrait être beaucoup plus compliqué
  return this.args.topic.my_metadata.status;
}
1 « J'aime »

Cela fonctionne à merveille. Merci d’avoir sauvé le reste de mon vendredi @david !!! J’apprécie beaucoup !!

2 « J'aime »

Ce sujet a été automatiquement fermé 30 jours après la dernière réponse. Les nouvelles réponses ne sont plus autorisées.