React.lazy 是干什么的
What is React lazy function
一句话:让组件按需加载—— 打包时被切成单独的 chunk, 真正渲染到它的时候才下载。 必须配 Suspense 给个占位。
为什么需要:SPA 默认把全站打成一个包, 首屏要下载所有页面的代码 (见 #321)。按路由切分是收益最大的一刀 —— 用户打开首页不该下载「设置页」的代码。
四个注意点:
lazy的参数必须返回一个带default导出的 Promise —— 所以配的是default export; 具名导出要自己包一层。- 动态
import()的路径不能是完全动态的变量, 打包工具需要在编译期能分析出来。 - 加载失败要有兜底—— 网络断了 chunk 拉不下来, 要用错误边界包住(见 #333)。这一点很多人不提,是加分项。
- 别切太碎 —— 每个 chunk 都是一次请求。
会追问:「怎么避免切换页面时闪一下 loading?」——预加载:鼠标悬停在链接上时 就调一次那个 import()(模块会被缓存)。 或者用 React 18 的useTransition让旧页面留在屏幕上直到新页面就绪。
In one line: it makes a component load on demand — the bundler cuts it into its own chunk, and the chunk is fetched only when you actually render it. It needs a Suspense around it to supply a placeholder.
Why you need it: by default an SPA is one bundle, so the first screen downloads the code for every page (see #321). Splitting per route is the highest-value cut — opening the home page should not download the settings page.
Four things to watch:
- What you pass to
lazymust return a Promise with adefaultexport — so it pairs withdefault export; a named export needs a small wrapper. - The path in a dynamic
import()cannot be a fully dynamic variable — the bundler has to be able to analyse it at build time. - Handle the failure case — if the network drops the chunk never arrives, so wrap it in an error boundary (see #333). Most people leave this out, so it is a bonus point.
- Do not split too finely — every chunk is another request.
Follow-up: “How do you avoid a loading flash when switching pages?” — preload: call that import() once when the mouse hovers the link (the module gets cached). Or use React 18’s useTransition to keep the old page on screen until the new one is ready.