LWCの子は@wiredApexクエリによって古いデータをキャッシュします。子はif:trueによって非表示になっているため、親はquerySelector()によって子のApex()を更新できません。何をすべきか?
簡単なアプリ構造(画像を参照):右側に「ラインアイテム」の子コンポーネントリスト(この写真では1601xCC5Bulkを1つだけ)、左側にパレット付きのコンテナー。<< Allocate btnは、フォームを使用して別の子モーダルを開きます(if:true ..)このフォームの選択リストは@wire apexを使用して空のパレットのみを表示するため、DML後にフォームのコントローラー自体によって更新されます。

右側の赤いボタンを使用するなど、親がパレットの量を変更する場合に問題が発生します。このDMLは、パレットとともにコンテナを削除します。
しかし、非表示のフォームが再び開かれた場合、古いパレット値が選択リスト値としてまだ存在しているので、そのデータを更新する必要があります。ただし、この子は非表示になっているため、標準では到達できません:parent-> querySelector(child2).method()
- newbの質問で申し訳ありません:非表示のコンポーネントのメソッドにアクセスする方法はありますか?
- また、Apexクエリの呼び出しを親コンポーネント(トリガーしやすい)まで移動し、それをapi引数として子モーダルに渡すことも考えていました。モーダルが表示されると、更新されたデータが取得されます。親が子供の負担を軽減するので、これは少し間違っていると感じます(多分私は間違っています)
- その頂点クエリに子のrenderedCallbackを使用することも考えていましたが、無限のレンダリングループを恐れていますか?
- auraEnabled apexのキャッシュを無効にするのは良いことですが、不可能のようです。
これが必要最低限のマークアップで、関連するすべての部分のみが表示されています
===親(2人の子供がいる)===
HTML
<template for:each={lineItems.data} for:item="lineItem">
<lightning-layout-item key={lineItem.Id} size="12">
<c-packing-list-line-item-card lineitem={lineItem} onallocatebuttonpress={openAllocationModal}></c-packing-list-line-item-card>
</lightning-layout-item>
</template>
<template if:true={isLineItemModalOpen}>
<c-packing-list-allocation-modal recordid={recordId} oncloseallocationmodal={closeAllocModal} onproductallocated={refreshData}></c-packing-list-allocation-modal>
</template>
JS
openAllocationModal(e) {
this.editItemId = e.detail;
this.isLineItemModalOpen = true;
}
closeAllocModal() {
this.isLineItemModalOpen = false;
}
=== CHILD 1:packing-list-line-item-card ===(右側の商品の詳細を示し、IDをモーダルに渡します)
HTML
<lightning-button variant="brand" label="<< Allocate" data-itemid={lineitem.Id} onclick={openAllocationModal}></lightning-button>
JS
openAllocationModal(e) {
const selectEvent = new CustomEvent('allocatebuttonpress', { detail: e.target.dataset.itemid });
this.dispatchEvent(selectEvent);
}
===子供2:割り当てモーダル(条件付き表示)===
HTML
<template if:true={showInsertButton}>
<button class="slds-button slds-button_brand" onclick={handleAllocationInsert}>Insert</button>
</template>
JS(おそらくcloseModal(){}にのみ興味があり、他のものは完全を期すためのものです)
handleAllocationInsert() {
[...]
createRecord(recordInput)
.then((allocId) => {
this.showToast('success', 'Success', 'Product Allocated');
this.handleInsert(this.palletValue);
this.refreshPallets();
})
.catch((error) => {
this.showToast('error', 'Error creating record', error.body.message);
this.closeModal();
});
}
closeModal() {
// On save parent closes modal
console.log('closing 1');
const selectEvent = new CustomEvent('closeallocationmodal');
this.dispatchEvent(selectEvent);
this.spinner = false;
}
handleInsert(palletValue) {
// On save parent refreshes container view
const selectEvent = new CustomEvent('productallocated', {
detail: this.palletcontainers[palletValue].containerId
});
this.dispatchEvent(selectEvent);
this.closeModal();
}
回答
newbの質問で申し訳ありません:非表示のコンポーネントのメソッドにアクセスする方法はありますか?
いいえ。子はDOMから物理的に削除され、まったく存在しなくなります(コンポーネントキャッシュにある可能性がある場合を除く)。
また、Apexクエリの呼び出しを親コンポーネント(トリガーしやすい)まで移動し、それをapi引数として子モーダルに渡すことも考えていました。モーダルが表示されると、更新されたデータが取得されます。親が子供の負担を軽減するので、これは少し間違っていると感じます(多分私は間違っています)
これは実際にはこれを行うための非常に標準的な方法です。子供はデータを表示することだけを心配する必要があります。それはそれがするように設計されていることです。一般に、コンポーネント階層のできるだけ高い位置でデータを取得/設定することをお勧めします(ただし、必要以上に高くしないでください)。
その頂点クエリに子のrenderedCallbackを使用することも考えていましたが、無限のレンダリングループを恐れていますか?
悪い考えですが、予想どおり、無限ループが発生します。ただし、ここでは、コンポーネントのconnectedCallbackを使用するのが理にかなっています。このイベントは、コンポーネントが追加されたとき、またはDOM内で移動されたときにのみ呼び出されるため、無限ループの問題は発生しません。
auraEnabled apexのキャッシュを無効にするのは良いことですが、不可能のようです。
それは完全に可能ですが、私はこれを最後の手段と考えます。ほとんどの場合、ユーザーが何かを行うまでデータは変更されないため、キャッシュによってパフォーマンスを向上させることができます。そうは言っても、デザインは頻繁な呼び出しを必要としないように見えるので、キャッシュを無効にすることもおそらく許容されます。
結論として、親からのデータを制御することが最も簡単な解決策になると思います。子コンポーネントは通常、親から提供されたデータでのみ機能するため、これはほとんどの場合、一般的に受け入れられるソリューションでもあります。たとえばlightning-input
、サーバーに対して直接何もしませんが、イベントを介して変更を親に伝達します。使用するのは完全に自然なデザインです。
子供たちに仕事を続けてもらいたい場合は、それでも構いません。connectedCallbackでrefreshApex呼び出しを行うか、キャッシュを無効にします。どちらでも問題は解決するはずですが、大規模なデータセットでテストして、利用可能なオプションのどれが最高のパフォーマンスを提供するかを確認することもできます。