跳到主要内容

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') 返回一个 Promise
  • React.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.lazyReact 官方推荐的懒加载方案


总结

  • React.lazy = 动态 import + Promise + Suspense 集成
  • 作用:实现组件级代码分割,按需加载,减小首屏体积
  • 必须配合 Suspense 使用
  • 不支持 SSR(需框架如 Next.js 解决)
  • 底层依赖现代打包工具的代码分割能力

🚀 最佳实践
对路由组件、大型 UI 模块(如图表、编辑器)使用 React.lazy,显著提升首屏性能。