ぬにょす(挨拶)。
今回紹介するのは、Next.js が提供する dynamic 関数を使って変数で指定したコンポーネントを読み込む方法です。
結論のコード
// 変数 component には、事前にコンポーネント名が格納されている
const DynamicComponent = dynamic(() =>
import("./module").then((mod: any) => mod[component])
);
Code language: TypeScript (typescript)
はじめに
Next.js には dynamic import という機能があります。
当該コンポーネントの表示が必要になったタイミングで import することで、最初のページ読み込みにおける転送量を減らすことができます。
この dynamic import で読み込むコンポーネントを変数で指定できないものかと思った次第です。
要するに
switch (arg) {
case "A":
DynamicComponent = dynamic(() => import("./A"));
break;
case "B":
DynamicComponent = dynamic(() => import("./B"));
break;
case "C":
DynamicComponent = dynamic(() => import("./C"));
break;
}
Code language: TypeScript (typescript)
みたいなことを
DynamicComponent = dynamic(() => import(`./${arg}`))
Code language: TypeScript (typescript)
のように書けないもんかな、と。
import()に変数を渡してもダメっぽい
最初はこれでイケるんじゃないかと思ったのですが。
// 何らかの事前処理で modulePath に "../components/hello" をセットした上で
const DynamicComponent = dynamic(() => import(modulePath))
Code language: JavaScript (javascript)
期待通りの動きにはなりませんでした。
変数経由だと、コンパイルなりビルドなりの時点では読み込むモジュール名が不明ですからね。
生成された js ファイルに、当該モジュールのコードが入らないんだと推測してます。
名前つきexportを応用してみた
Next.js 公式サイトの dynamic import のページには、名前つきで export されたコンポーネントを dynamic import する例が載っています。
以下、一部引用。
const DynamicComponent = dynamic(() =>
import('../components/hello').then((mod) => mod.Hello)
)
Code language: TypeScript (typescript)
“../components/hello” を読み込んだ後、モジュールに含まれる “Hello” というコンポネントを返却しているように解釈できます。
mod.Hello
は mod オブジェクトの Hello メンバにアクセスしているわけだから
// 何らかの事前処理で moduleName に "Hello" をセットした上で
const DynamicComponent = dynamic(() =>
import('../components/hello').then((mod) => mod[moduleName])
)
Code language: JavaScript (javascript)
という書き方と等価なんじゃないか?と思って試してみたらビンゴでした。
まとめ
- import() の引数に変数を渡してもダメ。
- import() の引数には文字列リテラルを指定し、使用するファイル(モジュール)を明確にした上で読み込むコンポーネントを変数で指定することは可能。
後書き
何故このようなコードが必要になったかというと、react-icons パッケージのアイコン一覧を表示する必要があったからです。
100を超える import を書く気はしなかったので、外部jsonファイルから読み込んだコンポーネント名を使って import できないかと試行錯誤した結果、今回紹介した方法を見つけた次第です。
コメント