El estado @tracked de un array u objeto dentro de un componente de Glimmer no activa actualizaciones cuando cambias un miembro del array/objeto.
Este tema habla sobre algunas opciones para que tu vista se actualice correctamente. Quería añadir otra forma, ya que las opciones que se comentan allí no me funcionaron.
Cómo lo resolví es: en lugar de asignar un elemento a la vez, asigna el array completo de una vez. La misma estrategia funcionaría con un objeto o cualquier otra estructura de datos.
En un componente de 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
})
// ESTA ES LA LÍNEA A NOTAR
// Debido a que usamos = directamente en el array, esto activará una actualización.
// Mientras que añadir al array o establecer elementos por índice no activaría una actualización.
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);
}
}
Podrías hacer esto también con una actualización parcial. Lo importante es que JavaScript detecte que se está asignando un valor diferente. Así que, aunque .concat funcionará, porque genera un nuevo array distinto del anterior:
this.categories = this.categories.concat(newValue)
Probablemente .push no funcionará, porque el array resultante es el mismo ID de objeto que el original, por lo tanto, JavaScript piensa que nada ha cambiado.
this.categories.push(newValue)
this.categories = this.categories
Si estás trabajando con un objeto, una forma fácil de generar uno nuevo es con Object.assign() - que crea una nueva estructura de datos extendida, como .concat arriba.
Esto ha sido así durante mucho tiempo para otros frameworks como Vue.js también; puedes encontrar temas sobre esto que se remontan a 10 años. Tiene que ver con la forma en que se implementa en JavaScript, probablemente con getters/setters en el objeto padre o con la API observe. Pero si se implementa con la API observe, entonces hay un poco menos de excusa para este comportamiento, ya que sería fácil activar el flag subtree… Quizás no lo eligen por preocupaciones de rendimiento al observar una estructura profundamente anidada. Pero me desvío, estos son detalles de implementación de las bibliotecas subyacentes. La solución alternativa anterior debería ayudarte a navegar esto.