Next.js - Dynamic Import

김명성·2022년 4월 24일
4

Next.js

목록 보기
5/7

Dynamic Import

Next.js는 ES2020의 Dynamic import를 지원한다.
이를 통해 동적으로 자바스크립트 모듈을 가져와 사용할 수 있다.
또한 Dynamic import 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>
  )
}

Dynamic import는 코드를 관리가능한 단위(chunks)로 분할하는 또 다른 방법으로 생각할 수 있다.

React Components는 Dynamic imports를 사용하여 import할 수도 있지만 이 경우 next/dynamic과 함께 사용하여 다른 React components처럼 동작하는지 확인한다.

다음 예제에서 ../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

위 예제에서 DynamicComponents는 ../components/hello에서 반환되는 default Component가 된다.
일반 React의 Component처럼 동작하며, props 또한 전달 가능하다.

다만 import(path/to/component)에 템플릿 문자열이나 변수를 사용할 수 없다.
또한 import()는 webpack의 번들/모듈 ID를 dynamic()호출과 일치시켜 렌더링 이전에 로드할 수 있도록 dynamic()호출 내부에 있어야 한다.
dynamic()은 React.lazy와 유사하게 사전 로드가 작동하도록 모듈의 최상위 수준에 표시되어야 하므로 React 렌더링 내부에서 사용할 수 없다.

With named exports

Dynamic component가 default export가 아니라면, 작명하여 export로 사용할 수 있다. 작명된 component를 Dynamic import로 가져오려면 import()에 의해 반환된 Promise에서 반환할 수 있다.

//components/hello.js
export function Hello() {
  return <p>Hello!</p>
}
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

With custom loading component

Dynamic import로 설정된 Component가 로드되는 동안, Loading state를 추가할 수 있다.

import dynamic from 'next/dynamic'

const DynamicComponentWithCustomLoading = dynamic(
  () => import('../components/hello'),
  { loading: () => <p>...</p> }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithCustomLoading />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

With no 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

With suspense

Option suspense를 사용하면 React.lazy 및 React18의 <Suspense>와 유사한 Component를 lazy-load할 수 있다.

import dynamic from 'next/dynamic'

const DynamicLazyComponent = dynamic(() => import('../components/hello4'), {
  suspense: true,
})

function Home() {
  return (
    <div>
      <Suspense fallback={`loading`}>
        <DynamicLazyComponent />
      </Suspense>
    </div>
  )
}

0개의 댓글