怎么优化 React 性能
How could you improve performance in React
先说这一句,再列手段:「先用 React DevTools Profiler 找出到底哪个组件渲染慢、渲染了多少次, 再决定动哪。」上来就背 useMemo会显得像背题。
手段分三类:
① 少渲染
React.memo+useMemo+useCallback三件套配套用(#346)- state 下移—— 把频繁变的 state 放到真正需要它的那个小组件里, 别提到顶层带着整棵树重渲染。这招常常比加 memo 有效得多。
- 用
children组合—— 父组件重渲染时, 作为 prop 传进来的 children不会重建。 - 拆分 Context —— 一个 context 里放太多东西, 改任何一项所有消费者都重渲染。
② 少下载
- 代码分割——
React.lazy+Suspense,按路由切(#347) - 按需引入第三方库,别
import _ from "lodash" - 用 bundle analyzer 看谁占体积
③ 少算 / 少画
- 长列表虚拟化—— 只渲染视口内的几十行。一万行的列表,这一条比其他所有优化加起来都有用。
- 列表 key 用稳定 id(#330)
- 输入防抖、搜索节流
- React 18 的
useTransition/useDeferredValue—— 让重活不挡住输入
会追问:「怎么知道有没有多余渲染?」—— Profiler 的「Highlight updates」 或者 <Profiler onRender>; 以及注意 StrictMode 下开发模式会渲染两次, 别把它当成 bug。
Open with this sentence, then list the techniques: “First I use the React DevTools Profiler to find which component is slow and how many times it renders, then I decide what to touch.” Reciting useMemo straight away sounds like you memorised an answer sheet.
Three families of technique:
① Render less
React.memo+useMemo+useCallbackused as a set (#346)- Push state down — put frequently changing state in the small component that actually needs it instead of lifting it to the top and re-rendering the whole tree. This often helps far more than adding memo.
- Compose with
children— when the parent re-renders, children passed in as a prop are not rebuilt. - Split your contexts — put too much in one context and changing any field re-renders every consumer.
② Download less
- Code splitting —
React.lazy+Suspense, split per route (#347) - Import third-party libraries piecemeal, not
import _ from "lodash" - Run a bundle analyzer to see who is taking up the space
③ Compute less, paint less
- Virtualise long lists — render only the few dozen rows in the viewport. On a ten-thousand-row list this beats every other optimisation put together.
- Use stable ids as list keys (#330)
- Debounce input, throttle search
- React 18’s
useTransition/useDeferredValue— keep the heavy work from blocking typing
Follow-up: “How do you know there are wasted renders?” — the Profiler’s “Highlight updates”, or <Profiler onRender>; and remember StrictMode renders twice in development, so do not mistake that for a bug.