lazy๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง๋  ๋•Œ๊นŒ์ง€ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๋ฅผ ๋กœ๋”ฉํ•˜๋Š” ๊ฒƒ์„ ์ง€์—ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const SomeComponent = lazy(load)

๋ ˆํผ๋Ÿฐ์Šค

lazy(load)

lazy๋ฅผ ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ ํ˜ธ์ถœํ•˜์—ฌ ์ง€์—ฐ ๋กœ๋”ฉ๋œ React ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ ์–ธํ•˜์„ธ์š”.

import { lazy } from 'react';

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

์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • load: Promise ํ˜น์€ ๋˜ ๋‹ค๋ฅธ thenable (then ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” Promise ์œ ์‚ฌ ๊ฐ์ฒด)์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. React๋Š” ๋ฐ˜ํ™˜๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฒ˜์Œ ๋ Œ๋”๋งํ•˜๋ ค๊ณ  ์‹œ๋„ํ•  ๋•Œ๊นŒ์ง€ load๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. React๊ฐ€ ์ฒ˜์Œ์œผ๋กœ load๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ๊ทธ๊ฒƒ์ด ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ๊ทธ ํ›„ ํ•ด๊ฒฐ๋œ ๊ฐ’์˜ .default๋ฅผ React ์ปดํฌ๋„ŒํŠธ๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜๋œ Promise์™€ Promise์˜ ํ•ด๊ฒฐ๋œ ๊ฐ’์€ ์บ์‹œ๋˜๋ฏ€๋กœ, React๋Š” load๋ฅผ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ Promise๊ฐ€ ๊ฑฐ๋ถ€๋˜๋ฉด, React๋Š” ๊ฑฐ๋ถ€ ์ด์œ ๋ฅผ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด Error Boundary๊ฐ€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก throw ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

lazy๋Š” ํŠธ๋ฆฌ์— ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋Š” React ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๊ฐ€ ์—ฌ์ „ํžˆ ๋กœ๋”ฉ๋˜๋Š” ๋™์•ˆ ๋ Œ๋”๋ง์„ ์‹œ๋„ํ•˜๋ฉด ์ผ์‹œ ์ค‘์ง€๋ฉ๋‹ˆ๋‹ค. ๋กœ๋”ฉ ์ค‘์— Loading Indicator๋ฅผ ํ‘œ์‹œํ•˜๋ ค๋ฉด <Suspense>๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.


load ํ•จ์ˆ˜

๋งค๊ฐœ๋ณ€์ˆ˜

load๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

Promise ๋˜๋Š” ๋‹ค๋ฅธ thenable (then ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” Promise ์œ ์‚ฌ ๊ฐ์ฒด)์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ .default ํ”„๋กœํผํ‹ฐ๊ฐ€ ํ•จ์ˆ˜, memo, forwardRef ์ปดํฌ๋„ŒํŠธ์™€ ๊ฐ™์€ ์œ ํšจํ•œ React ์ปดํฌ๋„ŒํŠธ ์œ ํ˜•์ธ ๊ฐ์ฒด๋กœ ํ•ด์„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


์‚ฌ์šฉ๋ฒ•

Suspense์™€ ์ง€์—ฐ ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ

์ผ๋ฐ˜์ ์œผ๋กœ ์ •์  import ์„ ์–ธ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

import MarkdownPreview from './MarkdownPreview.js';

ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง ๋  ๋•Œ๊นŒ์ง€ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์„ ์—ฐ๊ธฐํ•˜๋ ค๋ฉด import๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

import { lazy } from 'react';

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

์œ„์˜ ์ฝ”๋“œ๋Š” ๋™์  import()์— ์˜์กดํ•˜๋ฏ€๋กœ ๋ฒˆ๋“ค๋Ÿฌ ๋˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ง€์›์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ž„ํฌํŠธํ•˜๋ ค๋Š” lazy ์ปดํฌ๋„ŒํŠธ๊ฐ€ default ๋‚ด๋ณด๋‚ด๊ธฐ๋กœ ๋‚ด๋ณด๋‚ด์ ธ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์š”์ฒญ์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๊ฐ€ ๋กœ๋”ฉ๋˜๋ฏ€๋กœ, ๋กœ๋”ฉํ•˜๋Š” ๋™์•ˆ ํ‘œ์‹œํ•  ํ•ญ๋ชฉ๋„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. lazy ์ปดํฌ๋„ŒํŠธ ๋˜๋Š” ํ•ด๋‹น ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ ์ค‘ ํ•˜๋‚˜๋ฅผ <Suspense> ๊ฒฝ๊ณ„Boundary๋กœ ๊ฐ์‹ธ์„œ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<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() {
// ...
}