好的,我们来深入讲解 React.Suspense
的实际用法场景,从简单到高级逐步展开,涵盖:
- ✅ 组件懒加载:React.lazy 配合 Suspense
- 🚦 路由懒加载:
react-router-dom
中的懒加载路由 - 🧠 异步数据加载:结合
React Query
的 Suspense 模式 - 🌐 服务端渲染支持(Streaming / Server Components)
- 🔁 嵌套 Suspense 的控制粒度优化
1. ✅ 组件懒加载(最常见)
1 2 3 4 5 6 7 8 9 10 11 12 |
import { Suspense, lazy } from 'react' const Chart = lazy(() => import('./Chart')) function Dashboard() { return ( <Suspense fallback={<div>Loading chart...</div>}> <Chart /> </Suspense> ) } |
👉 优点:不加载 Chart 页面时,Chart 不会被打包进首屏 bundle,减小体积。
2. 🚦 路由懒加载(React Router 6+)
1 2 3 4 5 6 7 8 9 10 11 |
// routes.jsx import { lazy } from 'react' const Home = lazy(() => import('./pages/Home')) const About = lazy(() => import('./pages/About')) export const routes = [ { path: '/', element: <Home /> }, { path: '/about', element: <About /> }, ] |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// App.jsx import { useRoutes } from 'react-router-dom' import { routes } from './routes' import { Suspense } from 'react' export default function App() { const elements = useRoutes(routes) return ( <Suspense fallback={<div>页面加载中...</div>}> {elements} </Suspense> ) } |
✅ 实现页面级组件按需加载,和 Webpack/Vite 的代码分割完美结合。
3. 🧠 Suspense + React Query(异步数据加载)
React Query 支持在 5.x+ 中使用 Suspense 模式(默认需开启)
1 2 |
npm install @tanstack/react-query |
1 2 3 4 5 6 7 |
// fetchData.js export const fetchUser = async () => { const res = await fetch('/api/user') if (!res.ok) throw new Error('Failed to fetch') return res.json() } |
1 2 3 4 5 6 7 8 9 10 11 12 |
// UserInfo.jsx import { useSuspenseQuery } from '@tanstack/react-query' import { fetchUser } from './fetchData' function UserInfo() { const { data } = useSuspenseQuery({ queryKey: ['user'], queryFn: fetchUser, }) return <div>Hello, {data.name}</div> } |
1 2 3 4 5 |
// App.jsx <Suspense fallback={<div>用户信息加载中...</div>}> <UserInfo /> </Suspense> |
📌 特点:
useSuspenseQuery
会自动“挂起”组件渲染,直到数据准备好。- 优化用户体验:无需
isLoading
判断逻辑,配合 Suspense 自动处理等待状态。
4. 🌐 Suspense 支持服务端渲染(React 18+)
React 18+ 中,Suspense 支持 SSR streaming。也就是:先渲染页面结构、再增量“注入”懒加载部分。
1 2 3 4 |
<Suspense fallback={<SkeletonPage />}> <PageWithHeavyData /> </Suspense> |
👉 在服务端渲染(如使用 react-dom/server
的 pipeToNodeWritable
)中,用户可更早看到“骨架屏”,优化首屏体验。
5. 🔁 嵌套 Suspense 提高粒度控制
1 2 3 4 5 6 7 8 |
<Suspense fallback={<div>整体加载中...</div>}> <Header /> <Suspense fallback={<div>内容加载中...</div>}> <MainContent /> </Suspense> <Footer /> </Suspense> |
- 外层 Suspense 控制整个页面级 fallback(用于首屏)
- 内层 Suspense 可以为局部异步区域提供细粒度 loading 控制
✅ 总结:你该什么时候用 Suspense
?
使用场景 | 推荐方式 |
---|---|
加载异步组件 | React.lazy + Suspense |
页面懒加载(React Router) | lazy(() => import()) 配合 Suspense |
异步数据加载 | 搭配 React Query / Relay 等支持 Suspense 的数据库 |
SSR 优化 | 利用 React 18 的 Streaming SSR,搭配嵌套 Suspense |
多层嵌套 loading 控制 | 多个 Suspense ,控制粒度和 fallback UI |