@tracked 状態の配列またはオブジェクトが、配列/オブジェクトのメンバーを変更しても、glimmer コンポーネント内で更新をトリガーしないことがあります。
このトピックでは、いくつかのオプションについて説明しています。ここでは、私のビューが正しく更新されるようにするための別の方法を追加したいと思います。ここで説明されているオプションは私には機能しませんでした。
私がこれを解決した方法は次のとおりです。要素を 1 つずつ割り当てるのではなく、配列全体を一度に割り当てます。この同じ戦略は、オブジェクトやその他のデータ構造でも機能します。
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
})
// ここが注目すべき行です
// 配列に直接 = を使用するため、更新がトリガーされます。
// 配列にプッシュしたり、インデックスで要素を設定したりしても更新はトリガーされません。
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);
}
}
部分的な更新でもこれを行うことができます。重要なのは、JavaScript が 異なる値 が割り当てられていることを検出することです。したがって、.concat は機能しますが、それは古い配列とは異なる新しい配列を生成するためです。
this.categories = this.categories.concat(newValue)
.push を使用すると、結果の配列は元の配列と同じオブジェクト ID になるため、何も変更されていないと JavaScript が判断するため、おそらく機能しません。
this.categories.push(newValue)
this.categories = this.categories
オブジェクトを操作している場合、新しいオブジェクトを生成する簡単な方法は Object.assign() です。これは、上記の .concat のように、新しい拡張データ構造を作成します。
これは、Vue.js などの他のフレームワークでも長い間同様でした。この問題に関するトピックは 10 年前までさかのぼることができます。これは JavaScript での実装方法に関連しており、おそらく親オブジェクトのゲッター/セッターまたは observe API のいずれかです。しかし、それが observe API で実装されている場合、subtree フラグを簡単に切り替えることができるため、この動作には少し言い訳が少なくなります… パフォーマンス上の懸念から、深くネストされた構造を監視する場合にこれを選択しないのかもしれません。しかし、それはさておき、これらは基盤となるライブラリの実装の詳細です。上記の回避策は、これをナビゲートするのに役立つはずです。