Next.jsのdynamic importをもっと動的に

Next.js

ぬにょす(挨拶)。

今回紹介するのは、Next.js が提供する dynamic 関数を使って変数で指定したコンポーネントを読み込む方法です。

スポンサーリンク

結論のコード

// 変数 component には、事前にコンポーネント名が格納されている const DynamicComponent = dynamic(() => import("./module").then((mod: any) => mod[component]) );
Code language: TypeScript (typescript)

はじめに

Next.js には dynamic import という機能があります。

Optimizing: Lazy Loading | Next.js
Lazy load imported libraries and React Components to improve your application's overall loading performance.

当該コンポーネントの表示が必要になったタイミングで 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 できないかと試行錯誤した結果、今回紹介した方法を見つけた次第です。

コメント