コンポーネントの動的なインスタンス化

コンポーネントの動的なインスタンス化は、必ずしも必要ではない大きなモジュールの読み込みを回避するために役立ちます。また、基盤となるコンポーネントのコンストラクタが実行時まで知らされない場合でも、コンポーネントインスタンスをインスタンス化できます。動的インポートは、コンポーネントのカスタマイズの自由度を高める便利な解決方法です。ただし、実行時にパフォーマンスのオーバヘッドが発生するため、最良の解決方法ではない場合もあり、過度に使用しないように注意してください。

Lightning Web コンポーネントを動的にインポートおよびインスタンス化するには、Lightning Web セキュリティを有効化する必要があります。

動的コンポーネントをインスタンス化するには、コンポーネントの設定ファイルに lightning__dynamicComponent 機能を含める必要がある。次に例を示します。

この機能を使用するには、apiVersion プロパティを 55.0 以降に設定する必要があります。

コンポーネントの設定ファイルの詳細については、「コンポーネントの設定ファイル」を参照してください。

コンポーネントを動的にインスタンス化するには、<lwc:component> 管理要素をコンポーネントの HTML ファイルで lwc:is ディレクティブと共に使用します。

次に、<lwc:component> を使用する HTML テンプレートを示します。

<lwc:component> は指定された動的コンポーネントを表示する DOM のプレースホルダとして機能します。<lwc:component> は、lwc:is ディレクティブと共に使用する必要があります。

lwc:is ディレクティブは、<lwc:component> 管理要素に、実行時にインポートされるコンストラクタを提供します。lwc:is は、実行時に LightningElement コンストラクタを解決する式を受け取ります。

コンストラクタが偽値 (falsy) の場合、<lwc:component> タグとその子要素は表示されません。

式の値が定義されているが、LightningElement コンストラクタではない場合、エラーがスローされます。

コンポーネントの JavaScript ファイルで、import() 動的インポート構文を使用してカスタム要素をインポートします。

import() コールは、LightningElement コンストラクタを解決する Promise を返します。次にその要素が lwc:component プレースホルダの代わりに表示されます。動的コンポーネントに使用されるタグ名は、特定のコンストラクタで返される値です。

通常のコンポーネントと同様に、動的コンポーネントはインスタンス化され、DOM に添付されます。動的コンポーネントのコンストラクタが変更されると、既存の要素は DOM から削除されます。

次の例では、インポートが完了すると次のような HTML が表示されます。

then() メソッドを使用する代わりに、asyncawait 演算子を使用してコンポーネントのコンストラクタを返すこともできます。

カスタム要素を選択するには、その要素が DOM にあらかじめ添付されている必要があります。動的コンポーネントを選択するには、lwc:ref ディレクティブを使用するか、クラス名などのコンポーネントに割り当てられた属性を使用します。

動的コンポーネントが DOM に添付されているかどうかを確認する手順は、次のとおりです。

  • 動的コンポーネントで connectedCallback を使用して、DOM に添付されたときに通知します。
  • 親コンポーネントで renderedCallback を使用して、動的コンポーネントが DOM に添付されたことを検出します。

HTMLElement に適用可能なサポート対象の HTML 属性はすべて、lwc:component にも適用できます。

たとえば、次のような例が考えられます。

動的コンポーネントには子要素を含めることができます。<lwc:component> は最初に動的コンポーネントをレンダリングし、次にその子コンポーネントをレンダリングします。動的コンポーネントが変更されるたびに、既存の要素はすべての子要素と共に DOM から削除されます。新しい動的コンポーネントが、その子コンポーネントと共に表示されます。

動的コンポーネントは管理パッケージでのみ使用できます。ロック解除済みパッケージでは、動的コンポーネントはサポートされません。

動的インポートは本質的に「動的」であるため、フレームワークで、そのモジュールは事前に取得されません。この動作は、ユーザエクスペリエンスに悪影響を及ぼす可能性があります。

静的インポートステートメントを使用すると、フレームワークは実行時にコンポーネントとすべての連動関係を 1 つの JavaScript ファイルで配信します。動的にインポートされるコンポーネントを取得するときに、コンテンツがブラウザの HTTP キャッシュにまだ保存されていない場合、フレームワークはネットワークを往復する必要があります。

この例では、BundleExample コンポーネントクラスが StaticImport コンポーネントクラスと共に、1 つの JavaScript モジュールとしてブラウザに提供されます。DynamicImport コンポーネントクラスは、実行時、loadModule 関数が呼び出されたときに取得されます。

動的コンポーネントを使用する場合は、次の推奨事項に留意してください。

現時点では実装されていませんが、将来のフレームワークの最適化では、動的インポートが静的に分析可能な場合、コードを最適化できる可能性があります。次のように JavaScript 文字列リテラルを import() 関数に渡します。

動的インポートを静的に分析できない状況は、常にあり得ます。特に、コンポーネント名がメタデータを介して定義されている場合が、これに当てはまります。それ以外の場合は、将来的なフレームワークの最適化を利用できるように、動的インポートはすべて静的に解析できるようにすることを強くお勧めします。

動的インポートは、コンポーネントのカスタマイズの自由度を高める便利な解決方法です。ただし、実行時にパフォーマンスのオーバヘッドが発生するため、最良の解決方法ではない場合もあります。この場合の注意が必要な状況についていくつかの例を挙げて説明します。

この最初の例では、グラフコンポーネント c/chart を作成します。グラフの種類を公開プロパティとして受け取り、棒グラフ、円グラフ、折れ線グラフのいずれかに設定できます。このコンポーネントは内部的に、c/barChart、c/pieChart、または c/lineChart コンポーネントのいずれかを使用して、種類に基づいてグラフを表示します。

c/barChartc/pieChartc/lineChart のバンドルサイズの合計が小さい場合は、静的インポートを使用して実行時のネットワークの往復処理を避けるように c/chart コンポーネントを更新することをお勧めします。通常は、静的インポートから始めることをお勧めします。そして厳密に必要ではないコンポーネントのインポートによってパフォーマンスの問題が生じる場合には、動的インポートを使用してください。

3 つのモジュールすべてを静的にインポートするとバンドルサイズが大きくなり実行時のパフォーマンスに悪影響が出る場合でも、静的に解析できない動的インポートを静的に解析可能なインポートに変更するように、サンプルを更新することは可能です。

この考え方を説明する別の例を次に示します。この例では、エンティティ項目の値を表示する c/field コンポーネントを作成します。これは標準コンポーネントなので、この項目の表示に使用するコンポーネントの名前であるレンダラーの公開プロパティを受け取ります。前の例とは異なり、c/field コンポーネントは任意のコンポーネント名を受け入れる可能性があるため、既知のレンダラーのリストは事前には知らされません。

よりパフォーマンスが向上する方法として、c/field コンポーネントが、レンダラーのコンストラクタをコンポーネント名ではなく、公開プロパティとして受け取る方法があります。これは、コンポーネントが Lightning アプリケーションビルダーなどのビルダーに公開されていない場合にのみ機能します。

この代替設計では、項目コンポーネントはレンダラーのコンポーネントクラスの読み込みを親に委任します。これにより親コンポーネントは、その要件に応じて静的インポートまたは動的インポートのいずれかを使用できるようになります。

関連トピック