React.lazy 和 Suspense 的用法
在 React 中,React.lazy 和 Suspense 是用于实现代码分割(Code Splitting)和懒加载组件的重要特性。它们可以帮助你将大型应用拆分成更小的代码块,按需加载,从而提升初始加载性能。
一、React.lazy
✅ 作用
React.lazy() 允许你将一个动态导入的组件渲染为一个常规的 React 组件。它使得组件的代码可以在需要时才被加载(即懒加载)。
📌 语法
jsx
const LazyComponent = React.lazy(() => import('./LazyComponent'));
import('./LazyComponent'):返回一个 Promise,当模块加载完成时解析。React.lazy()会等待这个 Promise resolve,然后渲染导出的默认组件。
⚠️ 注意:被
lazy()包装的组件必须有一个 默认导出(default export)。
二、Suspense
✅ 作用
由于 React.lazy() 是异步加载组件的,Suspense 用于在等待懒加载组件完成渲染时显示一个“备用内容”(如 loading spinner)。
📌 语法
jsx
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>
fallback:当懒加载组件还在加载中时显示的内容(可以是任意 React 元素)。<Suspense>只能包裹一个子节点,但可以用 Fragment<>...</>。
三、完整示例
jsx
import React, { Suspense } from 'react';
// 👇 lazy load the component
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<div>
<h1>My App</h1>
{/* 👇 Use Suspense to show a fallback while loading */}
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
</div>
);
}
export default App;
对应的 ./HeavyComponent.jsx(必须有默认导出):
jsx
// HeavyComponent.jsx
import React from 'react';
const HeavyComponent = () => {
return (
<div style={{ padding: '20px', background: '#f0f0f0' }}>
This is a heavy component loaded lazily!
</div>
);
};
export default HeavyComponent; // ✅ must be default export
四、多个懒加载组件 + Suspense
你可以将多个懒加载组件放在同一个 <Suspense> 下:
jsx
<Suspense fallback={<LoadingSpinner />}>
<Header />
<MainContent />
<Sidebar />
</Suspense>
如果其中任何一个子组件是懒加载的且未就绪,整个区域都会显示 fallback。
##五、错误处理(配合 Error Boundary)
由于网络问题可能导致模块加载失败,建议结合 Error Boundary使用:
jsx
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return this.props.children;
}
}
// Usage:
<ErrorBoundary>
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>
</ErrorBoundary>
这样即使懒加载失败也不会白屏崩溃。
##六、服务端渲染(SSR)注意事项
⚠️ React.lazy 不支持服务端渲染。如果你需要做 SSR,可以考虑使用第三方库如 @loadable/component。
##七、命名导出怎么办?
如果模块是命名导出(export const MyComp),不能直接用 lazy,需包装一下:
jsx
const NamedExportedComp = React.lazy(() =>
import('./SomeModule').then(module => ({
default: module.NamedExportedComp,
}))
);
或者更简洁地写成:
plaintext
const mod = await import('./SomeModule'); // Assume named export is "NamedExportedComp"
return { default: mod.NamedExportedComp };
});
##总结:关键点回顾
| Feature | Description |
|---|---|
React.lazy(fn) |
fn returns a dynamic import (Promise), used for code splitting. |
| Requires | Default export in the imported module. |
<Suspense> |
Shows fallback UI while waiting for lazy components. |
| Multiple lazy components | Can be wrapped together under one Suspense. |
| Error handling | Use Error Boundary to catch loading failures. |
| Not SSR-friendly | Avoid with Next.js server-side rendering unless using alternatives like @loadable. |
通过合理使用 React.lazy + Suspense,可以显著提升大型应用的性能和用户体验。