Problem bei der Verfolgung verschachtelter Strukturen

Ich füge eine Glimmer-Komponente in topic-above-footer-buttons ein. Diese Glimmer-Komponente versucht, einige Metadaten über das Thema anzuzeigen. Ich serialisiere diese in topic.my_metadata.

Wenn die Metadaten aus einem Hintergrundjob aktualisiert werden(!), wird das Thema über MessageBus.publish(\"/topic/#{topic.id}\", { reload_topic: true, refresh_stream: true }) aktualisiert.

Dies wird nun korrekt in der Vorlage aktualisiert:

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

Wenn ich jedoch über einen Getter darauf zugreife:

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

dann wird {{ this.statusMessage }} nicht aktualisiert.

(Und dasselbe gilt für alle Getter, die auf irgendeine Weise von this.args.topic.my_metadata abhängen. Das ist das eigentliche Problem).

Was mache ich falsch?

Ich habe bereits vieles versucht, darunter die Definition benutzerdefinierter Ereignisse, das Kopieren von topic.my_metadata in ein @tracked metadata und dann die Verwendung von this.metadata usw.

1 „Gefällt mir“

Ich glaube, Sie haben nur dann eine Garantie, dass ein Getter neu ausgewertet wird, wenn einer der Werte, auf die er angewiesen ist, verfolgt wird (und sich ändert).

In diesem Fall ist {{this.args.topic.my_metadata.status}} meiner Meinung nach besser, obwohl Sie es übrigens so schreiben sollten: {{@topic.my_metadata.status}}.

2 „Gefällt mir“

Nun, es ist keine Frage von “besser” oder nicht, es gibt viel Logik in Javascript, die die Metadaten auswertet und zum Beispiel entscheidet, ob ein Button angezeigt werden soll, wie zum Beispiel

get showButton() {
   // tue einige rechenintensive Dinge mit this.args.topic.my_metadata.foo und this.args.topic.my_metadata.bar
}

daher brauche ich die Getter und ich brauche sie, um sich irgendwie neu zu bewerten.

Zusätzlich besagt die Glimmer-Dokumentation, dass args und seine Werte automatisch verfolgt werden.

Wenn die Vorlage sie automatisch verfolgen kann, warum kann der Getter das nicht?

Selbst das funktioniert, indem die Metadaten als Argument übergeben werden

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

mit

  getStatus(arg) {
    return arg.status;
  }

Dies ist ein unglücklicher Teil unserer Umstellung von Embers ‘classic’ Reaktivitätssystem (get/set/computed) auf das ‘octane’ @tracked / native-getters.

Wie oben besprochen, besteht das Problem mit Ihrem Beispiel darin, dass Sie von einem nativen Getter auf eine Nicht-@tracked-Eigenschaft zugreifen.

Der direkte Zugriff auf den vollständigen Pfad von einer Vorlage aus funktioniert, schränkt jedoch, wie Sie sagen, die verfügbare Logik ein.

Alternativ ermöglicht die Verwendung von .get() Embers neuem Autotracking-System, mit klassischen (d. h. nicht @tracked) Eigenschaften zu arbeiten.

In diesem Fall wäre es also

get statusMessage() {
  return this.args.topic.get("my_metadata.status");
}
4 „Gefällt mir“

Danke David

Könnten Sie das auch mit @computed lösen, oder ist das ein No-Go?

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

Ich glaube, das hätte den Vorteil, das Ergebnis zu cachen, wenn die Berechnung signifikant wäre.

(offensichtlich trivial in diesem Beispiel, aber etwas, das @RGJ angedeutet hat)

@computed ist Teil von Embers klassischem Reaktionssystem. Es ist nicht offiziell veraltet, aber wir versuchen, es in neuem Code zu vermeiden.

Wenn Ihr Getter kompliziert genug ist, um eine Zwischenspeicherung zu rechtfertigen, können Sie @cached verwenden:

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

...

@cached
get statusMessage() {
  // dies könnte viel komplizierter sein
  return this.args.topic.my_metadata.status;
}
1 „Gefällt mir“

Das funktioniert wie am Schnürchen. Vielen Dank, dass Sie mir den Rest meines Freitags gerettet haben, @david!!! Sehr geschätzt!!

2 „Gefällt mir“

Dieses Thema wurde 30 Tage nach der letzten Antwort automatisch geschlossen. Neue Antworten sind nicht mehr möglich.