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