React.lazy 和 Suspense 如何使用?原理是什么?
基本用法
import { lazy, Suspense } from 'react'
const Dashboard = lazy(() => import('./Dashboard'))
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Dashboard />
</Suspense>
)
}
路由级懒加载
import { lazy, Suspense } from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
const Home = lazy(() => import('./pages/Home'))
const About = lazy(() => import('./pages/About'))
function App() {
return (
<BrowserRouter>
<Suspense fallback={<PageLoader />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</BrowserRouter>
)
}
原理
React.lazy 返回一个特殊组件,内部状态为 pending
- 触发
import() 动态加载模块(返回 Promise)
- React 渲染时发现组件处于
pending,抛出 Promise
- 最近的
Suspense 边界捕获 Promise,渲染 fallback
- Promise resolve 后(模块加载完成),React 重新渲染,显示真实组件
function lazy(loader) {
let Component = null
return function LazyComponent(props) {
if (!Component) {
throw loader().then(mod => {
Component = mod.default
})
}
return <Component {...props} />
}
}
多个懒加载组件
<Suspense fallback={<Loader />}>
<Header /> {}
<Main /> {}
<Footer /> {}
</Suspense>
<Suspense fallback={<PageLoader />}>
<Header />
<Suspense fallback={<MainLoader />}>
<Main />
</Suspense>
<Footer />
</Suspense>
React 18 服务端 Suspense
<Suspense fallback={<Spinner />}>
<Comments /> {}
</Suspense>
与 Error Boundary 配合
<ErrorBoundary fallback={<Error />}>
<Suspense fallback={<Loader />}>
<LazyComponent />
</Suspense>
</ErrorBoundary>
优势
- 按需加载:减小首屏包体积
- 声明式:不需要手动管理 loading 状态
- 可组合:Suspense 可嵌套
同分类其他题目