LWCの子は@wiredApexクエリによって古いデータをキャッシュします。子はif:trueによって非表示になっているため、親はquerySelector()によって子のApex()を更新できません。何をすべきか?

Aug 17 2020

簡単なアプリ構造(画像を参照):右側に「ラインアイテム」の子コンポーネントリスト(この写真では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();
    }

回答

4 sfdcfox Aug 17 2020 at 20:36

newbの質問で申し訳ありません:非表示のコンポーネントのメソッドにアクセスする方法はありますか?

いいえ。子はDOMから物理的に削除され、まったく存在なくなります(コンポーネントキャッシュにある可能性がある場合を除く)。

また、Apexクエリの呼び出しを親コンポーネント(トリガーしやすい)まで移動し、それをapi引数として子モーダルに渡すことも考えていました。モーダルが表示されると、更新されたデータが取得されます。親が子供の負担を軽減するので、これは少し間違っていると感じます(多分私は間違っています)

これは実際にはこれを行うための非常に標準的な方法です。子供はデータを表示することだけを心配する必要があります。それはそれがするように設計されていることです。一般に、コンポーネント階層のできるだけ高い位置でデータを取得/設定することをお勧めします(ただし、必要以上に高くしないでください)。

その頂点クエリに子のrenderedCallbackを使用することも考えていましたが、無限のレンダリングループを恐れていますか?

悪い考えですが、予想どおり、無限ループが発生します。ただし、ここでは、コンポーネントのconnectedCallbackを使用するのが理にかなっています。このイベントは、コンポーネントが追加されたとき、またはDOM内で移動されたときにのみ呼び出されるため、無限ループの問題は発生しません。

auraEnabled apexのキャッシュを無効にするのは良いことですが、不可能のようです。

それは完全に可能ですが、私はこれを最後の手段と考えます。ほとんどの場合、ユーザーが何かを行うまでデータは変更されないため、キャッシュによってパフォーマンスを向上させることができます。そうは言っても、デザインは頻繁な呼び出しを必要としないように見えるので、キャッシュを無効にすることもおそらく許容されます。


結論として、親からのデータを制御することが最も簡単な解決策になると思います。子コンポーネントは通常、親から提供されたデータでのみ機能するため、これはほとんどの場合、一般的に受け入れられるソリューションでもあります。たとえばlightning-input、サーバーに対して直接何もしませんが、イベントを介して変更を親に伝達します。使用するのは完全に自然なデザインです。

子供たちに仕事を続けてもらいたい場合は、それでも構いません。connectedCallbackでrefreshApex呼び出しを行うか、キャッシュを無効にします。どちらでも問題は解決するはずですが、大規模なデータセットでテストして、利用可能なオプションのどれが最高のパフォーマンスを提供するかを確認することもできます。