L’état @tracked d’un tableau ou d’un objet dans un composant Glimmer ne déclenche pas de mises à jour lorsque vous modifiez un membre du tableau/objet.
Ce sujet aborde quelques options pour que votre vue se mette à jour correctement. Je voulais ajouter une autre méthode, car les options abordées là-bas n’ont pas fonctionné pour moi.
Voici comment j’ai résolu ce problème : au lieu d’assigner un élément à la fois, assignez le tableau entier en une seule fois. Cette même stratégie fonctionnerait avec un objet ou toute autre structure de données.
Dans un composant Glimmer :
@tracked categories = [];
constructor() {
super(...arguments);
this.loadAllData();
}
async loadAllData() {
const categories = []
const waiting = this.siteSettings.county_fence_print_categories.split('|').map(async (cid, index) => {
const data = await this.loadData(`/c/${cid}/l/latest.json?period=monthly`)
return data.topic_list.topics
})
// C'EST LA LIGNE À REMARQUER
// Parce que nous utilisons = directement sur le tableau, cela déclenchera une mise à jour.
// Alors que pousser dans le tableau ou définir des éléments par index ne déclencherait pas de mise à jour.
this.categories = await Promise.all(waiting)
}
async loadData(url) {
try {
const data = await ajax(url);
//console.log(`Got data for ${url}:`, data)
return data
} catch (error) {
console.error(`Failed to get data for ${url}:`, error);
}
}
Vous pourriez faire cela avec une mise à jour partielle également. L’important est que JavaScript détecte qu’une valeur différente est assignée. Ainsi, bien que .concat fonctionne, car il génère un nouveau tableau distinct de l’ancien :
this.categories = this.categories.concat(newValue)
Utiliser .push ne fonctionnera probablement pas, car le tableau résultant a le même ID d’objet que l’original, donc JavaScript pense que rien n’a changé.
this.categories.push(newValue)
this.categories = this.categories
Si vous travaillez avec un objet, un moyen simple d’en générer un nouveau est d’utiliser Object.assign() - qui crée une nouvelle structure de données étendue, comme .concat ci-dessus.
C’est le cas depuis longtemps pour d’autres frameworks comme Vue.js également - vous pouvez trouver des sujets à ce sujet datant de 10 ans. Cela a à voir avec la façon dont c’est implémenté en JavaScript, probablement soit des getters/setters sur l’objet parent, soit l’API observe. Mais si c’est implémenté avec l’API observe, alors il y a un peu moins d’excuse pour ce comportement, car il serait facile d’activer le drapeau subtree… Peut-être qu’ils choisissent de ne pas le faire pour des raisons de performance lors de la surveillance d’une structure profondément imbriquée ? Mais je m’égare, ce sont des détails d’implémentation des bibliothèques sous-jacentes. La solution de contournement ci-dessus devrait vous aider à naviguer dans ce problème.