lazy

lazy дозволяє відкласти завантаження коду компонента до його першого рендерингу.

const SomeComponent = lazy(load)

Довідник

lazy(load)

Виклик lazy за межами ваших компонентів для оголошення ліниво завантажуваного React-компонента:

import { lazy } from 'react';

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

Дивіться більше прикладів нижче.

Параметри

  • load: Функція, яка повертає Promise або інший thenable (обіцянко-подібний об'єкт з методом then). React не буде викликати load до першої спроби відрендерити повернутий компонент. Після першого виклику load React дочекається його розв'язання, а потім відрендерить .default розв'язаного значення як React-компонент. І повернута обіцянка, і отримане значення обіцянки будуть закешовані, тому React не буде викликати load більше одного разу. Якщо обіцянка відхиляється, React видасть причину відхилення для найближчої межі помилки, яку потрібно обробити.

Повернення

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


завантажити функцію

Параметри

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

Повернення

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


Використання

Ліниве завантаження компонентів з Suspense

Зазвичай ви імпортуєте компоненти за допомогою статичної декларації імпорту:

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>
      )}
    </>
  );
}

// Add a fixed delay so you can see the loading state
function delayForDemo(promise) {
  return new Promise(resolve => {
    setTimeout(resolve, 2000);
  }).then(() => promise);
}
export default function Loading() {
  return <p><i>Loading...</i></p>;
}
import { Remarkable } from 'remarkable';

const md = new Remarkable();

export default function MarkdownPreview({ markdown }) {
  return (
    <div
      className="content"
      dangerouslySetInnerHTML={{__html: md.render(markdown)}}
    />
  );
}
{
  "dependencies": {
    "immer": "1.7.3",
    "react": "latest",
    "react-dom": "latest",
    "react-scripts": "latest",
    "remarkable": "2.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}
label {
  display: block;
}

input, textarea {
  margin-bottom: 10px;
}

body {
  min-height: 200px;
}

Ця демонстрація завантажується зі штучною затримкою. Наступного разу, коли ви знімете і знову встановите прапорець, Preview буде закешовано, тому стану завантаження не буде. Щоб знову побачити стан завантаження, натисніть "Скинути" на пісочниці.

Довідка про керування станами завантаження за допомогою Suspense.


Налагодження

Мій лінивий компонент несподівано скидає стан

Не оголошуйте ліниві компоненти всередині інших компонентів:

import { lazy } from 'react';

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

Натомість, завжди оголошуйте їх на верхньому рівні вашого модуля:

import { lazy } from 'react';

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

function Editor() {
  // ...
}