skysan's programming notebook

コーディングして思ったことなどを気ままに

LWCでも仮想スクロールしたい!

あけましておめでとうございます。

Lightning Web Components(以下、LWC)で仮想スクロールのサンプルを作りました。

f:id:skysan:20200102103032g:plain

背景

最近、Salesforceアプリ開発をしています。 選択可能なレコードの一覧を表示する時にlightning-datatableを使用したところ、レコードが100件を超えたあたりから描画の遅さが気になります。データ数が大きくなると、応答なしになることも・・・。

lightning-datatableには無限スクロール(enable-infinite-loading)設定があり、レコード数を減らすことで、初回表示時の描画を早くすることができます。 しかし、それを利用するとチェックボックスの値が再描画された時に消えてしまい、思い通りの挙動ができませんでした。

調査をしていく中で「仮想スクロール(virtual scroll)」というのを見つけたので、サンプルを作ってみました。※

ソースコードは実際の案件で利用しておらず、個人の趣味で検証したものを公開しています。

仮想スクロールとは

レコードすべてをレンダリングせず、表示部分のレコードのみをレンダリングする手法。

↓よくわかる解説記事

仮想スクロールのすヽめ - Qiita

検証

LWCのPlaygroundにて検証しました。

作ったリポジトリ

以下の記事を参考にLWC版を作成しました。

Build your Own Virtual Scroll - Part I - DEV Community 👩‍💻👨‍💻

仕組み

  1. 仮想スクロールのコンポーネントと表示するレコードのコンポーネントを用意
  2. スクロールする度に表示する高さと行の高さから表示するレコード範囲を算出
  3. 表示するレコードの配列を@trackしている変数に渡す
  4. LWCが変更があるレコードのみレンダリング(Shadow DOM)
  5. レコードをチェックしたとき、親コンポーネントに通知

詰まったところ

  • コンポーネントの初期化イベントconnectedCallbackでレコードを取得できない
    • 原因:レコードの取得を非同期にしているので、初期化処理が先に実行されている
    • 対策:getter/setterでレコードを取得する。
  • template for:each内で直接onchangeイベントを呼ぶとパラメータが取得できない。
    • 原因:Error: Disallowed method "cloneNode" in ShadowRoot.
    • 対策:別のコンポーネントにし、CustomEventで値を通知する。

所感

仮想スクロールの実装はLWCが頑張ってくれたので、意外とあっさりできました。レンダリングもパフォーマンスも良さげ。 LWCの仕様を理解する方にむしろ時間がかかりました。