最近没有开发任务,除了研究下安排的优化代码的任务,顺便看了下React.lazy源码!所以今天主要介绍 React.lazy 的实现原理!
React.lazy 是 React 16.6 引入的功能,用于实现组件懒加载,从而减少初次加载的 JavaScript 包体积,提升应用性能!
React.lazy 允许开发者动态导入组件,返回一个特殊的 LazyComponent。搭配 Suspense,可以在组件加载时显示占位内容!
import React, { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./About'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
React.lazy 的核心是利用 JavaScript 的动态导入和 React 的内部机制来实现按需加载。以下是其工作流程:
React.lazy 接受一个返回 Promise 的函数,该 Promise 解析为模块对象,通常包含 default 导出的组件!
❝这也是每个模块入口需要 default 导出,而组件不需要的原因。
动态导入基于 ES Modules 的 import() 语法,浏览器会异步加载指定的模块。
const lazyFactory = () => import('./LazyComponent');
React.lazy 将动态导入的 Promise 包装为一个内部的 LazyComponent 对象。这个对象包含了加载状态和组件引用。
LazyComponent 的结构大致如下:

LazyComponent 数据结构
{
_init: lazyInit, // 动态导入函数
_payload: {
_status: -1, // 未加载
_result: null, // 加载后的组件或错误
}
}
当 LazyComponent 首次渲染时,React 调用 _init(即动态导入函数),触发模块加载。加载期间,LazyComponent 保持 _status 为 0,并通过 Suspense 机制抛出 Promise,让 Suspense 捕获并显示 fallback 内容。
if (lazyComponent._status === -1) {
lazyComponent._status = 0;
const promise = lazyComponent._init();
promise.then(
module => {
lazyComponent._payload._status = 1;
lazyComponent._payload._result = module.default;
},
error => {
lazyComponent._payload._status = 2;
lazyComponent._payload._result = error;
}
);
throw promise; // 抛出 Promise,交给 Suspense 处理
}
React.lazy 具有内置缓存,同一个 LazyComponent 的动态导入只执行一次。加载完成后,_result 存储实际组件,后续渲染直接使用缓存的组件。
Suspense 捕获 LazyComponent 抛出的 Promise,并在 Promise 解析前渲染 fallback 内容。一旦 Promise 解析(即组件加载完成),Suspense 重新渲染 LazyComponent,显示实际组件。
import React, { Suspense } from 'react';
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
当然,当加载失败时,也可以使用 Error Boundary 捕获错误,防止应用可能崩溃。
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return<h1>Something went wrong.</h1>;
}
returnthis.props.children;
}
}