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

const SomeComponent = lazy(load)

Справочник

lazy(load)

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

import { lazy } from 'react';

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

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

Параметры

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

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

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


Функция load

Параметры

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

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

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


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

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

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

import MarkdownPreview from './MarkdownPreview.js';

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

import { lazy } from 'react';

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

Этот код опирается на динамический import(), который должен поддерживаться вашим бандлером или фреймворком.

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