Lazy Loading

Next.js의 Lazy loading (opens in a new tab)은 경로를 렌더링하는 데 필요한 JavaScript의 양을 줄여 애플리케이션의 초기 로딩 성능을 향상시키는 데 도움이 됩니다

이는 Client Components 및 가져온 라이브러리의 로딩을 연기하고, 필요할 때만 클라이언트 번들에 포함시키는 것을 허용합니다. 예를 들어, 사용자가 모달을 열기 위해 클릭할 때까지 모달 로딩을 연기할 수 있습니다.

Next.js에서 lazy loading을 구현하는 방법에는 두 가지가 있습니다:

  1. Using Dynamic Imports with next/dynamic
  2. Using React.lazy() (opens in a new tab) with Suspense (opens in a new tab)

기본적으로, Server Components는 자동으로 코드 분할 (opens in a new tab)되며, 서버에서 클라이언트로 UI 조각을 점진적으로 전송하는 스트리밍을 사용할 수 있습니다. Lazy loading은 Client Components에 적용됩니다.

next/dynamic

next/dynamicReact.lazy() (opens in a new tab)Suspense (opens in a new tab)의 복합체입니다. 이는 apppages 디렉토리에서 점진적인 마이그레이션을 허용하도록 동일하게 작동합니다.

Examples

next/dynamic을 사용하면 헤더 컴포넌트는 페이지의 초기 JavaScript 번들에 포함되지 않습니다. 페이지는 먼저 Suspense fallback을 렌더링한 후, Suspense 경계가 해결되면 Header 컴포넌트를 렌더링합니다.

import dynamic from 'next/dynamic'
 
const DynamicHeader = dynamic(() => import('../components/header'), {
  loading: () => <p>Loading...</p>,
})
 
export default function Home() {
  return <DynamicHeader />
}

알아두면 좋은 점: import('path/to/component')에서 경로는 명시적으로 작성해야 합니다. 템플릿 문자열이나 변수가 될 수 없습니다. 또한 import()dynamic() 호출 내에 있어야 Next.js가 웹팩 번들 / 모듈 ID를 특정 dynamic() 호출과 일치시켜 렌더링 전에 미리 로드할 수 있습니다. dynamic()은 React 렌더링 내에서 사용할 수 없으며, 미리 로드가 작동하려면 모듈의 최상위에 표시되어야 합니다. 이는 React.lazy와 유사합니다.

With named exports

명명된 내보내기를 동적으로 가져오려면, import() (opens in a new tab) 함수에서 반환된 Promise (opens in a new tab)에서 반환할 수 있습니다:

components/hello.js
export function Hello() {
  return <p>Hello!</p>
}
 
// pages/index.js
import dynamic from 'next/dynamic'
 
const DynamicComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello),
)

With no SSR

클라이언트 측에서 컴포넌트를 동적으로 로드하려면 ssr 옵션을 사용하여 서버 렌더링을 비활성화할 수 있습니다. 이는 window와 같은 브라우저 API에 의존하는 외부 종속성 또는 컴포넌트에 유용합니다.

import dynamic from 'next/dynamic'
 
const DynamicHeader = dynamic(() => import('../components/header'), {
  ssr: false,
})

With external libraries

이 예제는 퍼지 검색을 위해 외부 라이브러리 fuse.js를 사용합니다. 모듈은 사용자가 검색 입력란에 입력한 후에만 브라우저에서 로드됩니다.

import { useState } from 'react'
 
const names = ['Tim', 'Joe', 'Bel', '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>
  )
}