React.Lazy
React.lazy 是 React 提供的内置懒加载(Lazy Loading)机制,用于实现组件的动态导入和代码分割(Code Splitting),从而优化应用的初始加载性能。
一、核心原理
React.lazy 的本质是:
将组件的加载推迟到首次渲染时,并配合
Suspense实现加载状态的优雅降级。
它底层依赖于 JavaScript 的动态 import() 语法(返回 Promise),并将其封装为 React 可识别的组件形式。
二、工作流程
1. 定义懒加载组件
const LazyComponent = React.lazy(() => import('./MyComponent'));
import('./MyComponent')返回一个 PromiseReact.lazy接收这个 Promise,并返回一个特殊的 React 组件
2. 首次渲染时触发加载
当 <LazyComponent /> 首次被渲染时:
- React 检测到这是一个 lazy 组件
- 自动执行
import(),开始加载对应的代码块(通过 Webpack/Vite 等打包工具分割出的 chunk) - 同时抛出一个 Promise(这是 Suspense 能捕获的关键)
3. Suspense 捕获并显示 fallback
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
Suspense捕获到 lazy 组件抛出的 Promise- 立即渲染
fallback内容(如 loading) - 一旦 Promise resolve(代码加载完成),Suspense 会重新渲染,显示真实组件
4. 后续渲染直接使用缓存
- 组件代码加载成功后,React 会缓存模块结果
- 后续再渲染
<LazyComponent />时不再发起网络请求,直接使用已加载的组件
三、底层机制(简化版)
React.lazy 内部大致做了以下事情:
function lazy(loadComponent) {
return class LazyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { Component: null };
}
componentDidMount() {
// 调用传入的函数,获取 Promise
const promise = loadComponent();
// 当 Promise resolve 时,设置 state 触发更新
promise.then(module => {
this.setState({ Component: module.default });
});
}
render() {
const { Component } = this.state;
if (Component) {
return <Component {...this.props} />;
}
// 抛出 Promise 让 Suspense 捕获(实际 React 内部通过 Fiber 机制处理)
throw promise;
}
};
}
🔍 实际实现更复杂(基于 Fiber 架构和 Suspense 的集成),但逻辑类似。
四、关键特性
| 特性 | 说明 |
|---|---|
| 仅支持默认导出 | import() 必须 resolve 到 { default: Component } |
| 必须配合 Suspense | 否则会报错:“Lazy component suspended...” |
| 自动代码分割 | 打包工具(Webpack/Vite)会为每个 import() 生成独立 chunk |
| 按需加载 | 只在组件首次渲染时加载,减少首屏 bundle 体积 |
五、使用示例
import { Suspense, lazy } from 'react';
// 懒加载路由组件
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
function App() {
return (
<Router>
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</Router>
);
}
六、注意事项
❌ 1. 不支持服务端渲染(SSR)
React.lazy在 SSR 环境下会报错(因为import()是客户端特性)- 解决方案:
- 使用 Next.js(内置 SSR + 动态导入支持)
- 或在 SSR 时提供 fallback 组件
❌ 2. 不能在条件语句中使用
// ❌ 错误:违反 Hooks 规则(lazy 组件本质是特殊组件)
if (condition) {
const Comp = lazy(() => import('./Comp'));
}
✅ 3. 预加载(Preload)提升体验
const LazyComp = lazy(() => import('./Comp'));
// 在用户可能需要前预加载
LazyComp.preload?.(); // 自定义 preload 方法(需手动添加)
七、与传统代码分割对比
| 方式 | 是否自动分割 | 是否支持加载状态 | 是否 React 原生 |
|---|---|---|---|
React.lazy + Suspense | ✅ 是 | ✅ 是 | ✅ 是 |
import().then() 手动管理 | ✅ 是 | ❌ 需自行实现 | ❌ 否 |
| Webpack Magic Comments | ✅ 是 | ❌ | ❌ |
💡
React.lazy是 React 官方推荐的懒加载方案。
总结
React.lazy= 动态 import + Promise + Suspense 集成- 作用:实现组件级代码分割,按需加载,减小首屏体积
- 必须配合
Suspense使用 - 不支持 SSR(需框架如 Next.js 解决)
- 底层依赖现代打包工具的代码分割能力
🚀 最佳实践:
对路由组件、大型 UI 模块(如图表、编辑器)使用React.lazy,显著提升首屏性能。