🚀

【Next.js和訳】Advanced Features/Dynamic Import

4 min read

この記事について

株式会社 UnReact はプロジェクトの一環としてNext.js ドキュメントの和訳を行っています。

この記事は、Advanced Features/Dynamic Importの記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。


ダイナミックインポート

Next.jsは、JavaScriptのES2020 dynamic import()をサポートしています。これを使うと、JavaScriptモジュールを動的にインポートし、それらを扱うことができます。また、SSRでも動作します。

次の例では、fuse.jsを使ってファジー検索を実装し、ユーザーが検索入力をした後にのみ、ブラウザにモジュールを動的にロードします。

import { useState } from 'react'
const names = ['Tim', 'Joe', 'Bel', 'Max', 'Lee']
export default function Page() {
  const [results, setResults] = useState()
  return (
    <div>
      <input
        type="text"
        placeholder="Search"
        onChange={async (e) => {
          const { value } = e.currentTarget
          // Dynamically load fuse.js
          const Fuse = (await import('fuse.js')).default
          const fuse = new Fuse(names)
          setResults(fuse.search(value))
        }}
      />
      <pre>Results: {JSON.stringify(results, null, 2)}</pre>
    </div>
  )
}

ダイナミックインポートは、コードを管理可能なチャンクに分割する別の方法と考えることができます。

Reactコンポーネントもダイナミックインポートを使用してインポートすることができますが、今回は他のReactコンポーネントと同様に動作するようにnext/dynamicと組み合わせて使用しています。仕組みの詳細については、以下のセクションをチェックしてください。

基本的な使い方

以下の例では、モジュール ../components/hello がページによって動的に読み込まれます。

import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('../components/hello'))
function Home() {
  return (
    <div>
      <Header />
      <DynamicComponent />
      <p>HOME PAGE is here!</p>
    </div>
  )
}
export default Home

DynamicComponentは、../components/helloが返すデフォルトのコンポーネントになります。これは通常のReact Componentのように動作し、通常のようにpropsを渡すことができます。

注意
import('path/to/component')では、パスを明示的に記述する必要があります。テンプレート文字列や変数ではいけません。さらに、Next.jsがwebpackのバンドルやモジュールのIDを特定のdynamic()コールにマッチさせ、レンダリング前にプリロードするためには、import()dynamic()コールの中になければなりません。dynamic()は、React.lazyと同様に、プリロードが機能するためにモジュールのトップレベルでマークされる必要があるため、Reactレンダリングの内部では使用できません。

名前付きエクスポートの場合

ダイナミックコンポーネントがデフォルトのエクスポートでない場合、名前付きのエクスポートも使用できます。モジュール ../components/hello.js が名前付きエクスポート Hello を持っているとします:

export function Hello() {
  return <p>Hello!</p>
}

Helloコンポーネントを動的にインポートするには、import()が返すPromiseから次のようにして返します。

import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello)
)
function Home() {
  return (
    <div>
      <Header />
      <DynamicComponent />
      <p>HOME PAGE is here!</p>
    </div>
  )
}
export default Home

カスタムローディングコンポーネント

オプションのloadingコンポーネントを追加すると、ダイナミックコンポーネントのロード中にローディング状態をレンダリングすることができます。例えば、以下のようになります:

import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/hello3'),
  { ssr: false }
)
function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  )
}
export default Home

SSRなしの場合

あるモジュールをサーバーサイドに入れたいとは限らないでしょう。例えば、そのモジュールがブラウザ上でのみ動作するライブラリを含んでいる場合です。

以下の例を見てみましょう。

import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/hello3'),
  { ssr: false }
)
function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  )
}
export default Home

サスペンスとは

オプションのsuspenseを使うと、React.lazyやReact 18の<Suspense>のように、コンポーネントを遅延ロードすることができます。ただし、このオプションはクライアントサイドまたはfallback付きのサーバーサイドでのみ動作します。同時モードでのSSRの完全なサポートはまだ進行中です。

import dynamic from 'next/dynamic'
const DynamicLazyComponent = dynamic(() => import('../components/hello4'), {
  suspense: true,
})
function Home() {
  return (
    <div>
      <Suspense fallback={`loading`}>
        <DynamicLazyComponent />
      </Suspense>
    </div>
  )
}

Discussion

ログインするとコメントできます