lazy 允许你延迟加载组件代码,直到它首次被渲染时才加载。
const SomeComponent = lazy(load)参考
lazy(load)
在组件外部调用 lazy 来声明一个懒加载的 React 组件:
import { lazy } from 'react';
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));参数
load:一个返回 Promise 或其他 thenable(一种带有then方法、类似 Promise 的对象)的函数。React 不会在你第一次尝试渲染返回的组件之前调用load。在 React 首次调用load之后,它会等待其解析,然后将解析结果的.default作为 React 组件渲染。返回的 Promise 以及 Promise 的解析值都会被缓存,因此 React 不会多次调用load。如果 Promise 被拒绝,React 会将拒绝原因throw出来,由最近的错误边界处理。
返回值
lazy 返回一个你可以在树中渲染的 React 组件。当懒加载组件的代码仍在加载时,尝试渲染它会 suspend. 使用 <Suspense> 可以在加载期间显示加载指示器。
load 函数
参数
load 不接收任何参数。
返回值
你需要返回一个 Promise 或其他一些 thenable(一种带有 then 方法、类似 Promise 的对象)。它最终需要解析为一个对象,其 .default 属性是有效的 React 组件类型,例如函数、memo 或 forwardRef 组件。
用法
使用 Suspense 懒加载组件
通常,你会使用静态 import 声明来导入组件:
import MarkdownPreview from './MarkdownPreview.js';要将该组件的代码延迟到首次渲染时才加载,请将这个导入替换为:
import { lazy } from 'react';
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));这段代码依赖于 动态 import(), 这可能需要你的打包工具或框架提供支持。使用这种模式要求你导入的懒加载组件是以 default 导出的形式导出的。
现在组件的代码按需加载了,你还需要指定在加载期间应显示什么内容。你可以通过将懒加载组件或其任意父组件包裹进 <Suspense> 边界来实现:
<Suspense fallback={<Loading />}>
<h2>预览</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)} /> 显示预览 </label> <hr /> {showPreview && ( <Suspense fallback={<Loading />}> <h2>预览</h2> <MarkdownPreview markdown={markdown} /> </Suspense> )} </> ); } // 添加一个固定延迟,这样你就可以看到加载状态 function delayForDemo(promise) { return new Promise(resolve => { setTimeout(resolve, 2000); }).then(() => promise); }
这个演示会带有一个人为延迟进行加载。下次你取消勾选再勾选复选框时,Preview 会被缓存,因此不会再出现加载状态。要再次看到加载状态,请在 sandbox 中点击“Reset”。
故障排除
我的 lazy 组件状态会意外重置
不要在其他组件 内部 声明 lazy 组件:
import { lazy } from 'react';
function Editor() {
// 🔴 不好:这会导致在重新渲染时所有状态都被重置
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
// ...
}相反,请始终在模块顶层声明它们:
import { lazy } from 'react';
// ✅ 好:在组件外部声明懒加载组件
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
function Editor() {
// ...
}