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:
Der Klick-Handler wird korrekt ausgeführt
Die Eigenschaft item.expanded wird aktualisiert (im Konsolenprotokoll überprüft)
Aber die Vorlage rendert nicht neu – keine Klassenänderungen, keine Textänderungen
Was ich versucht habe:
Array-Neuzuweisung - this.items = [...this.items] nach der Mutation (funktioniert nicht)
Immer für unveränderliche Updates - Wollte dies versuchen, aber npm-Importe funktionieren in Discourse-Themes nicht
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?
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:
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.
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.
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.