Glimmer-Komponenten-Änderungserkennung funktioniert nicht – Mutieren von Eigenschaften im @tracked-Array

Hallo zusammen!

Ich habe Probleme mit der Änderungs Erkennung in einer Glimmer-Komponente und könnte etwas Hilfe gebrauchen. Wenn ich Eigenschaften von Objekten innerhalb eines @tracked-Arrays mutiere, rendert die Vorlage nicht neu.

Meine Einrichtung:

```javascript

import Component from '@glimmer/component';

import { tracked } from '@glimmer/tracking';

import { fn } from '@ember/helper';

import { on } from '@ember/modifier';

import { action } from '@ember/object';



export default class CustomSidebarComponent extends Component {

  @tracked items = [

    {

      id: 'home',

      label: 'Home',

      expanded: false

    },

    {

      id: 'my-posts', 
      label: 'My Posts',

      expanded: false

    }

    // ... weitere Elemente

  ];



  @action

  toggleExpanded(item) {

    item.expanded = !item.expanded; // Diese Mutation löst kein erneutes Rendern aus

    console.log('Toggled:', item.label, item.expanded); // Protokolliert korrekt

  }



  <template>
    <div id="custom-sidebar">
      <ul>
        {{#each this.items key="@index" as |item|}}
          <li class="menu-item {{if item.expanded 'expanded'}}" {{on "click" (fn this.toggleExpanded item)}}>
            {{item.label}} {{if item.expanded "(expanded)" ""}}
          </li>
        {{/each}}
      </ul>
    </div>
  </template>

}

```

Das Problem:

  1. Der Klick-Handler wird korrekt ausgeführt
  2. Die Eigenschaft item.expanded wird aktualisiert (im Konsolenprotokoll überprüft)
  3. Aber die Vorlage rendert nicht neu – keine Klassenänderungen, keine Textänderungen

Was ich versucht habe:

  1. Array-Neuzuweisung - this.items = [...this.items] nach der Mutation (funktioniert nicht)
  2. Immer für unveränderliche Updates - Wollte dies versuchen, aber npm-Importe funktionieren in Discourse-Themes nicht
  3. Andere Schlüsselstrategien - key="id" anstelle von key="@index"

Fragen:

  • Sollte das Mutieren von Eigenschaften von Objekten innerhalb von @tracked-Arrays in Glimmer funktionieren?
  • Muss ich einzelne Objekte irgendwie verfolgbar machen?
  • Gibt es ein empfohlenes Muster für diesen Anwendungsfall?
  • Könnte dies damit zusammenhängen, dass es in einer Discourse-Theme-Umgebung ausgeführt wird?
  • Gibt es Einschränkungen bei npm-Importen in Discourse-Themes, die sich auf Reaktivitätsbibliotheken auswirken?

Umgebung:

  • Discourse-Theme-Komponente
  • Glimmer-Komponenten mit .gjs-Dateien
  • Neueste Discourse-Version – heute aktualisiert

Jede Einsicht wäre sehr willkommen! Übersehe ich etwas Grundlegendes im Reaktivitätssystem von Glimmer?

Danke!

2 „Gefällt mir“

Hmm, das ist seltsam. Der Array-Zuweisungstrick funktioniert normalerweise.

Eine Alternative, die ich gefunden habe, besteht darin, die Objekte im Array aus einer Klasse mit eigenen nachverfolgten Eigenschaften zu machen. So etwas wie:

class CustomSidebarItem {
  @tracked expanded = false;
  constructor(id, label) {
    this.id = id;
    this.label = label;
  }
}

export default class CustomSidebarComponent extends Component {

  @tracked items = [
    new CustomSidebarItem('home', 'Home'),
    new CustomSidebarItem('my-posts', 'My Posts'),
    ...
  ];
  // Rest deines Codes
}

Es kann umständlicher sein als die Erstellung einer Reihe einfacher Objekte, aber ich habe festgestellt, dass es die Erweiterung und Argumentation erleichtert, insbesondere wenn Sie etwas tun müssen, wie z. B. die Daten an verschachtelte Komponenten weiterzugeben.

4 „Gefällt mir“

Hallo Alteras,

Vielen Dank für Ihren Vorschlag !!! Er hat wie von Ihnen vorgeschlagen funktioniert und unseren Tag wirklich ein wenig einfacher gemacht ::)** :grinning_face:

2 „Gefällt mir“

Ich glaube, wenn Sie ein Array wie im OP beschrieben verfolgen, verfolgen Sie die Array-Referenz und nicht Änderungen an den einzelnen Objekten innerhalb des Arrays.

Eine andere Möglichkeit, dies zu handhaben, ist die Verwendung von trackedObject. Wir verwenden dies an einigen Stellen in Discourse.

3 „Gefällt mir“

Vielen Dank für Ihre Eingaben. Ich habe noch eine weitere Anschlussfrage:

Würde die Verwendung einer Bibliothek wie Immer funktionieren?
Wenn ja, wie sollte ich Immer in Discourse einbinden?
Ich habe Hinweise gesehen, dass man sie „in Assets aus node_modules kopieren“ kann, aber ich würde es bevorzugen, wenn es eine Möglichkeit gäbe, dies über npm oder sogar einen CDN-Link im Header-Tag zu tun.

Sie können loadScript() verwenden, um JS zu laden, auch wenn die angegebene URL eine externe URL ist. Die Verwendung externer Dienste wie jsdelivr sollte damit funktionieren.

import loadScript from "discourse/lib/load-script";

...

loadScript(URL).then(() => {
   // Ihr Code
})

Obwohl ich es nicht ausgiebig getestet habe, sollte ein dynamischer Import ebenfalls funktionieren.

async function load() {
  const {
    default: myDefault,
    foo,
    bar,
  } = await import(URL);
  // Rest des Codes
}

Ich sollte anmerken, dass es wahrscheinlich sicherer ist, die NPM-Dateien direkt in Ihrem Code zu speichern, anstatt sich auf ein externes CDN zu verlassen, je nachdem, wie kritisch das JS ist. Ebenso müssen Sie möglicherweise ein wenig Bündeln und Vorverarbeiten durchführen, bevor Sie es im Browser verwenden können.


Ob Immer mit Discourse funktioniert, weiß ich nicht.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.