lazy cho phép bạn trì hoãn việc tải code của component cho tới khi được render lần đầu tiên.

const SomeComponent = lazy(load)

Tham khảo

lazy(load)

Gọi lazy bên ngoài các component của bạn để khai báo một React component được lazy-load:

import { lazy } from 'react';

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

Xem thêm ví dụ ở dưới.

Tham số

  • load: Một function trả về một Promise hoặc một thenable (một đối tượng giống Promise với một phương thức then). React sẽ không gọi hàm load cho tới khi bạn render component được trả về. Sau khi React gọi load lần đầu tiên, React sẽ đợi cho tới khi hàm này được giải quyết xong (resolve), sau đó sẽ render giá trị .default như một React component. Cả Promise được trả về và giá trị đã được giải quyết của Promise đó đều được lưu lại, nên React sẽ không gọi load thêm nữa. Nếu Promise từ chối, React sẽ throw lý do từ chối cho Error Boundary gần nhất để xử lý.

Giá trị trả về

lazy trả về một React component mà bạn có thể render. Khi đoạn code cho lazy component đó đang được tải, việc thực hiện render nó sẽ được hoãn lại. Sử dụng <Suspense> để hiển thị một chỉ báo đang tải (loading).


load function

Parameters

load receives no parameters.

Returns

You need to return a Promise or some other thenable (a Promise-like object with a then method). It needs to eventually resolve to an object whose .default property is a valid React component type, such as a function, memo, or a forwardRef component.


Các sử dụng

Lazy-loading components với Suspense

Thông thường, bạn import các component bằng khai báo tĩnh import:

import MarkdownPreview from './MarkdownPreview.js';

Để trì hoãn việc tải code của component cho tới khi nó được render lần đầu tiên, thay thế import với:

import { lazy } from 'react';

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

Đoạn code này phụ thuộc vào dynamic import(), có thể sẽ cần được hỗ trợ bởi bundler hoặc framework của bạn. Sử dụng mẫu này yêu cầu lazy component mà bạn đang import phải được export bằng default.

Bây giờ code của component sẽ tải khi được yêu cầu, bạn sẽ cần phải xác định cái gì sẽ được hiển thị khi component đang được tải. Bạn có thể làm điều này bằng việc bọc lazy component hoặc bất kì phần tử cha của nó vào trong <Suspense>:

<Suspense fallback={<Loading />}>
<h2>Preview</h2>
<MarkdownPreview />
</Suspense>

Trong ví dụ này, đoạn code cho MarkdownPreview sẽ không được tải cho tới khi bạn thực thi việc render nó. Nếu MarkdownPreview vẫn chưa được tải xong, Loading sẽ được hiển thị vào vị trí của nó. Hãy thử tích vào checkbox dưới đây:

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

// Thêm một khoảng thời gian trì hoãn để bạn có thể thấy được loading state
function delayForDemo(promise) {
  return new Promise(resolve => {
    setTimeout(resolve, 2000);
  }).then(() => promise);
}

Đoạn demo này được tải với một khoảng thời gian trì hoãn cố ý. Lần sau khi bạn bỏ chọn và chọn lại, Preview sẽ được lưu lại, lên sẽ không còn loading state nữa. Để nhìn lại loading state, hãy bấm “Reset” trên sandbox.

Tìm hiểu thêm về quản lý các loading state với Suspense.


Khắc phục sự cố

State của lazy component của tôi bị đặt lại ngoài ý muốn

Không khai báo các lazy component bên trong các component khác:

import { lazy } from 'react';

function Editor() {
// 🔴 Bad: Điều này sẽ khiến các state bị đặt lại khi render lại
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
// ...
}

Thay vào đó, luôn luôn khai báo chúng ở trên cùng module của bạn:

import { lazy } from 'react';

// ✅ Good: Khai báo các lazy component bên ngoài các component
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));

function Editor() {
// ...
}