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