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'));
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ứcthen
). React sẽ không gọi hàmload
cho tới khi bạn render component được trả về. Sau khi React gọiload
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ọiload
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() {
// ...
}