📍lazy
✅컴포넌트의 최초 렌더링까지 코드 로딩(예-import 문)을 지연시킬 수 있다
const SomeComponent = lazy(load)
📍lazy(load)
✅lazy loading 컴포넌트를 선언하기 위해 컴포넌트 바깥에서 lazy 함수를 호출한다
import { lazy } from 'react';
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
✅매개변수
load
- Promise 또는 .then() 과 함께 쓰이는 유사 Promise 객체를 리턴하는 함수
- lazy 함수로 반환한 컴포넌트가 최초 렌더링되고나서야 load 콜백 함수가 호출된다
- load 콜백 함수 호출이 로드된 후, resolve까지 대기했다가 resolve된 값이 React 컴포넌트로 렌더링된다
- load 콜백 함수가 반환하는 Promise와 그 Promise의 reslove 값 모두 캐시되므로, load는 1번만 호출된다
- 만약 Promise가 reject 되면, 가까운 곳에서 에러가 발생한다
✅반환값
- lazy api는 lazy 컴포넌트를 반환
- lazy 컴포넌트의 코드가 로드되는 중에 렌더링을 시도하면 suspend (중단) 된다
- <Suspense> 를 사용하여 로딩중 loading indicator를 표시할 수 있다
📍load 함수
✅매개변수
- 없음
✅반환값
- Promise 혹은 .then() 을 사용 가능한 유사 Promise 객체
- 반환되는 Promise는 유효한 React 컴포넌트로 resolve되어야 한다
함수, memo, forwardRef 컴포넌트 등..
📍Lazy-loading 컴포넌트 w/ Suspense
일반 import와 다르게, lazy api를 사용하면, 컴포넌트의 코드 로딩을 지연시킨다
import { lazy } from 'react';
//import MarkdownPreview from './MarkdownPreview.js'; // 이 코드 대신 아래처럼 import
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
이제 이 코드는 dynamic import 에 의존한다 (번들러 or 프레임워크의 기능 필요할 수 있음)
- dynamic import를 통해 on demand 방식으로 로딩 (요청 시 로딩)
- 코드가 로딩중일 때 무엇을 화면에 표시할지 명시해야 함
- 이는 lazy api가 반환하는 컴포넌트 (lazy component)를 Suspense 로 래핑하여 구현할 수 있다
<Suspense fallback={<Loading />}>
<h2>Preview</h2>
<MarkdownPreview />
</Suspense>
📍예제
https://beta.reactjs.org/reference/react/lazy#suspense-for-code-splitting
lazy
A JavaScript library for building user interfaces
beta.reactjs.org
- MarkdownPreview 컴포넌트는 렌더링을 시도하기 전까지는 로드되지 않는다
- 이 때, 로딩 전이므로 Loading 컴포넌트가 대신 렌더링된다
App.js
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);
}
Loading.js
export default function Loading() {
return <p><i>Loading...</i></p>;
}
MarkdownPreview.js
import { Remarkable } from 'remarkable';
const md = new Remarkable();
export default function MarkdownPreview({ markdown }) {
return (
<div
className="content"
dangerouslySetInnerHTML={{__html: md.render(markdown)}}
/>
);
}
📍주의사항
✅lazy component의 상태가 예기치 않게 리셋될 때
⭐lazy components는 컴포넌트 바깥에서 선언해야 한다