lazy
๋ ๋ก๋ฉ ์ค์ธ ์ปดํฌ๋ํธ ์ฝ๋๊ฐ ์ฒ์์ผ๋ก ๋ ๋๋ง ๋ ๋๊น์ง ์ฐ๊ธฐํ ์ ์์ต๋๋ค.
const SomeComponent = lazy(load)
๋ ํผ๋ฐ์ค
lazy(load)
lazy๋ฅผ ์ด์ฉํ์ฌ ๋ก๋ฉํ๋ React ์ปดํฌ๋ํธ๋ฅผ ์ ์ธํ๋ ค๋ฉด ์ปดํฌ๋ํธ ์ธ๋ถ์์ lazy
๋ฅผ ํธ์ถํ์ธ์.
import { lazy } from 'react';
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
์๋์์ ๋ ๋ง์ ์์๋ฅผ ํ์ธํ์ธ์.
๋งค๊ฐ๋ณ์
load
: Promise ๋๋ ๋ ๋ค๋ฅธ thenable (then
๋ฉ์๋๊ฐ ์๋ Promise ์ ์ฌ ๊ฐ์ฒด)์ ๋ฐํํ๋ ํจ์์ ๋๋ค. React๋ ๋ฐํ๋ ์ปดํฌ๋ํธ๋ฅผ ์ฒ์ ๋ ๋๋งํ๋ ค๊ณ ํ ๋๊น์งload
๋ฅผ ํธ์ถํ์ง ์์ ๊ฒ์ ๋๋ค. React๋ ๋จผ์ load
๋ฅผ ์คํํ ํload
๊ฐ ์ดํ๋ ๋๊น์ง ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์ดํ๋ ๊ฐ์ React ์ปดํฌ๋ํธ๋ก ๋ ๋๋งํฉ๋๋ค. ๋ฐํ๋ Promise์ Promise์ ์ดํ๋ ๊ฐ์ด ๋ชจ๋ ์บ์ ๋๋ฏ๋ก React๋load
๋ฅผ ๋ ๋ฒ ์ด์ ํธ์ถํ์ง ์์ต๋๋ค. Promise๊ฐ ๊ฑฐ๋ถํ๋ฉด React๋ ๊ฐ์ฅ ๊ฐ๊น์ด Error Boundary๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด Error Boundary์ ๋ํ ๊ฑฐ๋ถ ์ฌ์ ๋ฅผthrow
ํ ๊ฒ์ ๋๋ค.
๋ฐํ๊ฐ
lazy
๋ ํธ๋ฆฌ์ ๋ ๋๋งํ ์ ์๋ React ์ปดํฌ๋ํธ๋ฅผ ๋ฐํํฉ๋๋ค. ์ปดํฌ๋ํธ์ ์ฝ๋๊ฐ ์ฌ์ ํ ๋ก๋๋๋ ๋์ ๋ ๋๋ง์ ์๋ํ๋ฉด ์ผ์ ์ค์ง๋ฉ๋๋ค. ๋ก๋ฉ ์ค์ loading indicator๋ฅผ ํ์ํ๋ ค๋ฉด <Suspense>
๋ฅผ ์ฌ์ฉํฉ๋๋ค.
load
ํจ์
๋งค๊ฐ๋ณ์
load
๋ ๋งค๊ฐ๋ณ์๋ฅผ ์์ ํ์ง ์์ต๋๋ค.
๋ฐํ๊ฐ
Promise ๋๋ ๋ค๋ฅธ thenable (then
๋ฉ์๋๊ฐ ์๋ Promise ์ ์ฌ ๊ฐ์ฒด)์ ๋ฐํํด์ผ ํฉ๋๋ค. ๊ฒฐ๊ตญ ํจ์, memo
๋๋ forwardRef
์ปดํฌ๋ํธ์ ๊ฐ์ ์ ํจํ React ์ปดํฌ๋ํธ ์ ํ์ผ๋ก ์ดํํด์ผ ํฉ๋๋ค.
์ฌ์ฉ๋ฒ
Suspense์ Lazy-loading ์ปดํฌ๋ํธ
์ผ๋ฐ์ ์ผ๋ก ์ ์ import
์ ์ธ์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
import MarkdownPreview from './MarkdownPreview.js';
ํด๋น ์ปดํฌ๋ํธ ์ฝ๋๊ฐ ์ฒ์ ๋ ๋๋ง ๋ ๋๊น์ง ๋ก๋ํ๋ ๊ฒ์ ์ฐ๊ธฐํ๋ ค๋ฉด import๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋์ฒดํฉ๋๋ค.
import { lazy } from 'react';
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
์์ ์ฝ๋๋ ๋์ import()
์ ์์กดํ๋ฏ๋ก ๋ฒ๋ค๋ฌ ๋๋ ํ๋ ์์ํฌ์ ์ง์์ด ํ์ํ ์ ์์ต๋๋ค.
์ด์ ์์ฒญ์ ๋ฐ๋ผ ์ปดํฌ๋ํธ์ ์ฝ๋๊ฐ ๋ก๋๋๋ฏ๋ก ๋ก๋ํ๋ ๋์ ํ์ํ ํญ๋ชฉ๋ ์ง์ ํด์ผ ํฉ๋๋ค. 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> )} </> ); } // ๋ก๋ฉ ์ํ๋ฅผ ํ์ธํ๊ธฐ ์ํด, ํ ์คํธ๋ฅผ ์ํ ์ง์ฐ๊ฐ์ ์ถ๊ฐํฉ๋๋ค. function delayForDemo(promise) { return new Promise(resolve => { setTimeout(resolve, 2000); }).then(() => promise); }
์ด ๋ฐ๋ชจ๋ ์ธ์์ ์ธ ์ง์ฐ์ผ๋ก ๋ก๋๋ฉ๋๋ค. ๋ค์์ ์ฒดํฌ๋ฐ์ค๋ฅผ ์ ํ ํด์ ํ๊ณ ๋ค์ ์ ํํ๋ฉด Preview
๊ฐ ์บ์ ๋์ด ๋ก๋ฉ ์ํ๊ฐ ๋์ง ์์ต๋๋ค. ๋ก๋ฉ ์ํ๋ฅผ ๋ค์ ๋ณด๋ ค๋ฉด ์๋๋ฐ์ค์์ โResetโ์ ํด๋ฆญํ์ธ์.
Suspense๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๋ฉ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์ธํ ์์๋ณด์ธ์.
๋ฌธ์ ํด๊ฒฐ
lazy
์ปดํฌ๋ํธ์ ์ํ๊ฐ ์๋์น ์๊ฒ ์ฌ์ค์ ๋ฉ๋๋ค.
lazy
์ปดํฌ๋ํธ๋ฅผ ๋ค๋ฅธ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ์ ์ธํ์ง ๋ง์ธ์.
import { lazy } from 'react';
function Editor() {
// ๐ด ์๋ชป๋ ๋ฐฉ๋ฒ: ์ด๋ ๊ฒ ํ๋ฉด ๋ค์ ๋ ๋๋งํ ๋ ๋ชจ๋ ์ํ๊ฐ ์ฌ์ค์ ๋ฉ๋๋ค.
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
// ...
}
๋์ ํญ์ ๋ชจ๋์ ์ต์์ ์์ค์์ ์ ์ธํ์ธ์.
import { lazy } from 'react';
// โ
์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ: lazy ์ปดํฌ๋ํธ๋ฅผ ์ปดํฌ๋ํธ ์ธ๋ถ์ ์ ์ธํฉ๋๋ค.
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
function Editor() {
// ...
}