lazy

Chaerin Kim·2023년 12월 12일

lazy를 사용하면 컴포넌트의 코드가 처음 렌더링될 때까지 로딩을 지연시킬 수 있음.

const SomeComponent = lazy(load)

Reference

lazy(load)

컴포넌트 외부에서 lazy를 호출하여 lazy-loaded React 컴포넌트를 선언할 수 있음:

import { lazy } from 'react';

const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));

Parameters

  • load: Promise 또는 다른 thenable(then 메서드가 있는 Promise와 유사한 객체)을 반환하는 함수. React는 반환된 컴포넌트를 처음 렌더링하려고 시도할 때까지 load를 호출하지 않음. React가 load를 처음 호출한 후, resolve될 때까지 기다린 다음, resolved 값의 .default를 React 컴포넌트로 렌더링함. 반환된 Promise와 Promise의 resolved 값은 모두 캐시되므로 React는 load를 두 번 이상 호출하지 않음. Promise가 reject되면 React는 가장 가까운 Error Boundary에 rejection 이유를 throw함.

Returns

lazy는 트리에서 렌더링할 수 있는 React 컴포넌트를 반환함. lazy 컴포넌트의 코드가 로딩되는 동안에는 렌더링을 시도하면 일시 중단됨. 로딩하는 동안 loading indicator를 표시하려면 <Suspense>를 사용할 것.

load function

Parameters

parameters를 받지 않음.

Returns

Promise 또는 다른 thenable(then 메서드가 있는 Promise와 유사한 객체)을 반환해야함. 최종적으로 .default 프로퍼티는 함수, memo 또는 forwardRef 컴포넌트와 같은 유효한 React 컴포넌트 유형인 객체로 resolve되어야 함.


Usage

Lazy-loading components with Suspense

일반적으로 정적 import 선언을 사용하여 컴포넌트를 가져옴:

import MarkdownPreview from './MarkdownPreview.js';

이 컴포넌트의 코드가 처음 렌더링될 때까지 로딩을 지연시키려면 이 import를 다음으로 대체:

import { lazy } from 'react';

const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));

이 코드는 동적 import()에 의존하므로 번들러 또는 프레임워크의 지원이 필요할 수 있음. 이 패턴을 사용하려면 가져오려는 lazy 컴포넌트를 default export로 내보내야 함.

이제 컴포넌트의 코드는 필요할 때 로드되므로 로드하는 동안 표시할 내용도 지정해야 함. Lazy 컴포넌트나 그 부모 컴포넌트를 <Suspense> 바운더리로 감싸면 됨:

<Suspense fallback={<Loading />}>
  <h2>Preview</h2>
  <MarkdownPreview />
 </Suspense>

다음 예제에서는 렌더링을 시도하기 전까지 MarkdownPreview의 코드가 로드되지 않음. MarkdownPreview가 아직 로드되지 않은 경우, 그 자리에 <Loading />이 표시됨:

import { useState, Suspense, lazy } from 'react';
import Loading from './Loading.js';

const MarkdownPreview = lazy(() => delayForDemo(import('./MarkdownPreview.js')));

export default function MarkdownEditor() {
  const [showPreview, setShowPreview] = useState(false);
  const [markdown, setMarkdown] = useState('Hello, **world**!');
  return (
    <>
      <textarea value={markdown} onChange={e => setMarkdown(e.target.value)} />
      <label>
        <input type="checkbox" checked={showPreview} onChange={e => setShowPreview(e.target.checked)} />
        Show preview
      </label>
      <hr />
      {showPreview && (
        <Suspense fallback={<Loading />}>
          <h2>Preview</h2>
          <MarkdownPreview markdown={markdown} />
        </Suspense>
      )}
    </>
  );
}

// Add a fixed delay so you can see the loading state
function delayForDemo(promise) {
  return new Promise(resolve => {
    setTimeout(resolve, 2000);
  }).then(() => promise);
}

체크박스를 선택한 후 선택 해제했다가 다시 선택하면 Preview가 캐시되므로 로딩 상태가 표시되지 않음.

참고: Suspense로 로딩 상태를 관리하는 방법


Troubleshooting

My lazy component’s state gets reset unexpectedly

다른 컴포넌트 안에 지연 컴포넌트를 선언하지 말 것:

import { lazy } from 'react';

function Editor() {
  // 🔴 Bad: This will cause all state to be reset on re-renders
  const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
  
  // ...
}

대신 항상 모듈의 최상위 레벨에서 선언할 것:

import { lazy } from 'react';

// ✅ Good: Declare lazy components outside of your components
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));

function Editor() {
  
  // ...
}

0개의 댓글