Перейти к содержанию

lazy

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

1
const SomeComponent = lazy(load);

Описание

lazy(load)

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

1
2
3
4
5
import { lazy } from 'react';

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

Параметры

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

Возвращает

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

load функция

Параметры

load не получает никаких параметров.

Возвращает

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

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

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

Обычно вы импортируете компоненты с помощью объявления static import:

1
import MarkdownPreview from './MarkdownPreview.js';

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

1
2
3
4
5
import { lazy } from 'react';

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

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

Теперь, когда код вашего компонента загружается по требованию, вам также необходимо указать, что должно отображаться во время его загрузки. Вы можете сделать это, обернув ленивый компонент или любого из его родителей в границу <Suspense>:

1
2
3
4
<Suspense fallback={<Loading />}>
    <h2>Preview</h2>
    <MarkdownPreview />
</Suspense>

В этом примере код для MarkdownPreview не будет загружен, пока вы не попытаетесь его отобразить. Если MarkdownPreview еще не загрузился, вместо него будет показан Loading. Попробуйте установить флажок:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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>
            )}
        </>
    );
}

// Add a fixed delay so you can see the loading state
function delayForDemo(promise) {
    return new Promise((resolve) => {
        setTimeout(resolve, 2000);
    }).then(() => promise);
}
1
2
3
4
5
6
7
export default function Loading() {
    return (
        <p>
            <i>Loading...</i>
        </p>
    );
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { Remarkable } from 'remarkable';

const md = new Remarkable();

export default function MarkdownPreview({ markdown }) {
    return (
        <div
            className="content"
            dangerouslySetInnerHTML={{
                __html: md.render(markdown),
            }}
        />
    );
}

Эта демонстрация загружается с искусственной задержкой. В следующий раз, когда вы снимите и установите флажок, Preview будет кэширован, поэтому состояния загрузки не будет. Чтобы снова увидеть состояние загрузки, нажмите "Сброс" в песочнице.

Подробнее об управлении состояниями загрузки с помощью Suspense.

Устранение неполадок

Состояние моего компонента lazy неожиданно сбрасывается

Не объявляйте компоненты lazy внутри других компонентов:

1
2
3
4
5
6
7
8
9
import { lazy } from 'react';

function Editor() {
    // 🔴 Bad: This will cause all state to be reset on re-renders
    const MarkdownPreview = lazy(() =>
        import('./MarkdownPreview.js')
    );
    // ...
}

Вместо этого всегда объявляйте их на верхнем уровне вашего модуля:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import { lazy } from 'react';

// ✅ Good: Declare lazy components outside of your components
const MarkdownPreview = lazy(() =>
    import('./MarkdownPreview.js')
);

function Editor() {
    // ...
}

Источник — https://react.dev/reference/react/lazy

Комментарии