lazy позволяет отложить загрузку кода компонента до его первого рендеринга.

const SomeComponent = lazy(load)

Справочник

lazy(load)

Вызовите lazy вне ваших компонентов, чтобы объявить компонент React с ленивой загрузкой:

import { lazy } from 'react';

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

См. другие примеры ниже.

Параметры

  • load: Функция, которая возвращает Промис или другой thenable (объект, в котором определен метод then). Вызова load не произойдет до тех пор, пока вы не попытаетесь отрендерить возвращённый компонент. После первого вызова load, React будет ждать завершения выполнения команды, а затем отрендерит разрешённое значение .default как React-компонент. Возвращаемый промис и разрешённое значение промиса будут кэшироваться, поэтому React не будет вызывать load более одного раза. Если Promise отклоняется, React укажет причину в ближайшем Error Boundary.

Возвращаемое значение

lazy возвращает React-компонент, который можно отрендерить в вашем дереве. Пока код для ленивого компонента все еще загружается, попытка его отрисовки приостанавливается. Используйте <Suspense> для отображения индикатора загрузки во время загрузки.


Функция load

Параметры

load не принимает параметров.

Возвращаемое значение

Возвращает Промис или другой thenable (объект, в котором определен метод then). В конечном итоге он вернёт объект со свойством .default, принимающим валидный React-компонент, например функцию, memo, или forwardRef-компонент.


Использование

Ленивая загрузка компонентов с Suspense

Обычно импорт компонентов происходит со статическим import объявлением:

import MarkdownPreview from './MarkdownPreview.js';

Чтобы отложить загрузку кода этого компонента до его первого рендеринга, замените этот импорт на:

import { lazy } from 'react';

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

Этот код опирается на динамический import(), который должен поддерживаться вашим бандлером или фреймворком. Использование этого подхода требует, чтобы импортируемый компонент был экспортирован с помощью экспорта по умолчанию.

Теперь, когда код вашего компонента загружается по запросу, вам также необходимо указать, что должно отображаться во время его загрузки. Это можно сделать путем оборачивания ленивого компонента или его родителя в границы <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() {
// ...
}