目次
dynamic import(動的インポート)について
dynamic import(動的インポート)とは動的にimportを実行するための機能です。ES2020でJavaScriptの仕様として導入されました。dynamic importを利用すると非同期でモジュールを読み込めます。
例えば、初期表示で読み込み不要なモジュールにdynamic importを適用すると初期ロードの負荷を軽減でき、表示速度を改善できます。
Next.jsでdynamic importを利用する方法
Next.jsはdynamic importをサポートしており、next/dynamicで利用できます。
import対象がdefault exportなのかnamed exportなのかによってdynamic importの記述方法が異なります。以下ではそれぞれについて紹介します。
default export(デフォルトエクスポート)をdynamic importする場合
../components/hello
というモジュール(ファイル)でdefault exportされたコンポーネントをdynamic importする場合は以下のようになります。
import dynamic from "next/dynamic";
const DynamicComponent = dynamic(() => import('../components/hello'));
named export(名前付きエクスポート)をdynamic importする場合
../components/hello
というモジュール(ファイル)でnamed exportされたコンポーネントをdynamic importする場合は以下のようになります。
named exportの場合はthen()
でモジュールを受け取り、モジュールを通じてコンポーネントにアクセスします。
export側
export const Hello = () => {
return <p>Hello!</p>;
};
import側
import dynamic from "next/dynamic"
// JSXの場合はdynamicの直後の『<{}>』は不要
const Hello = dynamic<{}>(() =>
import("../components/hello").then((module) => module.Hello)
);
Next.jsにおけるdynamic importのつかいどころ
Next.jsにおけるdynamic importのつかいどころは主に『SSR回避』と『ロード時のパフォーマンス改善』の2点です。
以下ではそれぞれについて紹介します。
dynamic importを利用したSSR回避について
Next.jsのページのレンダリングはデフォルトでPre-rendering、つまりSSR(Server-side Rendering)もしくはSSG(Static Site Generation)です。1
サーバサイドではブラウザの機能は利用できないので、サーバサイドでのレンダリング時にブラウザの機能を利用すると以下のようなサーバエラーになります。
上記の問題はSSR回避のオプション(ssr: false
)を付与したdynamic importによって解決できます。
SSR回避とはサーバサイドで処理が実行されないように制御することです。サーバサイドで実行するとサーバエラーになってしまう処理に対してSSR回避が利用されます。
以下のコードはdynamic importを利用したSSR回避の例です。
dynamic importによりサーバサイドでWindowが参照されなくなるため、サーバエラーを防げます。
import dynamic from "next/dynamic";
const Alert = dynamic(() => import("../components/Alert"), { ssr: false });
const App = () => {
return (
<>
<div>App Page</div>
<Alert />
</>
);
};
export default App;
// サーバサードで当該コンポーネントを呼び出すとwindowが参照できずサーバエラーになる
const Alert: React.FC = () => {
const showAlert = () => {
window.alert("Hello");
};
return <>{showAlert()}</>;
};
export default Alert;
dynamic importを利用したロード時のパフォーマンス改善
初回表示で不要なモジュールにdynamic importを適用することにより、ロード時の読み込み対象が減るためパフォーマンス改善につながります。
以下は初期表示でロードする必要のないLargeList
コンポーネントをdynamic importで非同期に読み込む例です。
import { useState } from "react";
import dynamic from "next/dynamic";
// Listコンポーネントはサイズが大きく初期表示の遅延の原因になるものと想定
const LargeList = dynamic(() => import("../components/LargeList"));
const App = () => {
const [isVisible, setIsVisible] = useState(false);
return (
<>
<button onClick={() => setIsVisible(!isVisible)}>
Toggle Visible Status
</button>
{isVisible && <LargeList />}
</>
);
};
export default App;
next/dynamicのオプションについて
next/dynamicにはSSR回避をはじめとしたオプションが用意されています。next/dynamicのオプションは以下の通りです。2
- ssr
- suspense
- loading
以下ではそれぞれについて紹介します。
ssr: SSR回避するためのオプション
サーバサイドで呼び出したくないコンポーネントに対して使うオプションです。
SSR回避のサンプルコードは前述したため省略します。
loading: カスタムローディングを利用するためのオプション
dynamic importが完了するまでの間の画面表示をカスタマイズしたい時に利用するオプションです。
{ loading: () => ローディング中に表示させたい内容}
とすることでカスタムローディングを実装できます。
具体的なコードは以下の通りです。
以下の例ではLargeList
コンポーネントをロードしている間、LargeList
コンポーネントの代わりにNow Loading...
の文字列が表示されます。
import { useState } from "react";
import dynamic from "next/dynamic";
const LargeList = dynamic(() => import("../components/LargeList"), {
loading: () => <p>Now Loading...</p>,
});
const App = () => {
const [isVisible, setIsVisible] = useState(false);
return (
<>
<button onClick={() => setIsVisible(!isVisible)}>
Toggle Visible Status
</button>
{isVisible && <LargeList />}
</>
);
};
export default App;
ローディング時間が短すぎてloadingの挙動がわかりにくい場合はChrome DevToolsのNetworkタブから通信速度の変更をします。
通信速度の変更方法はChrome DevtoolsのNetwork features reference#Emulate slow network connectionsを参考にしてください。
suspense: Suspenseコンポーネントと組み合わせる場合のオプション
dynamic importしたコンポーネントを<Suspense>
の子コンポーネントで利用する場合に使うオプションです。
Suspense
はreact 18で正式導入される機能です3。2021年11月現在、reactの最新版は17.0.2ですのでsuspenseの説明はNext.js『Dynamic Import#With suspense』の参考実装を紹介するだけにとどめておきます。
// https://nextjs.org/docs/advanced-features/dynamic-import#with-suspense より引用
import dynamic from 'next/dynamic'
const DynamicLazyComponent = dynamic(() => import('../components/hello4'), {
suspense: true,
})
function Home() {
return (
<div>
<Suspense fallback={`loading`}>
<DynamicLazyComponent />
</Suspense>
</div>
)
}
今回のまとめ
- dynamic importを利用すると非同期でimport処理ができる
- named exportとdefault exportでdynamic importの記述方法が異なる
- Next.jsにおけるdynamic importの使いどころSSR回避とロード時のパフォーマンス改善
- dynamic importのオプションにはssr, loading, suspenseがある
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!