React 性能优化方法
React 性能优化方法
1. 避免不必要的重新渲染
React.memo(缓存组件)
const Child = React.memo(({ name }: { name: string }) => {
return <div>{name}</div>;
});
props 没变就跳过渲染。
useCallback(缓存函数引用)
const handleClick = useCallback(() => {
console.log(count);
}, [count]);
防止父组件重渲染时,函数引用变化导致子组件不必要的渲染。
useMemo(缓存计算结果)
const result = useMemo(() => {
return heavyCalc(list);
}, [list]);
避免每次渲染都重复计算。
2. 合理拆分组件和状态
状态放到离它最近的组件,避免顶层 state 变化导致大范围重渲染:
// ❌ 不好:count 在顶层,变化导致整棵树渲染
function App() {
const [count, setCount] = useState(0);
return (
<>
<HeavyList /> {/* 和 count 无关,却被迫重渲染 */}
<Counter count={count} onChange={setCount} />
</>
);
}
// ✅ 好:count 状态下移到 Counter 内部
function App() {
return (
<>
<HeavyList />
<Counter />
</>
);
}
3. 列表渲染加 key
items.map((item) => <Item key={item.id} data={item} />);
正确的 key 帮助 React diff 算法复用节点,避免不必要的重建。
4. 懒加载组件(代码分割)
import { lazy, Suspense } from "react";
const HeavyPage = lazy(() => import("./HeavyPage"));
function App() {
return (
<Suspense fallback={<div>加载中...</div>}>
<HeavyPage />
</Suspense>
);
}
按需加载,减少首屏 JS 体积。
5. 虚拟列表(长列表优化)
大量列表只渲染可视区域的元素:
import { FixedSizeList } from "react-window";
<FixedSizeList height={600} itemCount={10000} itemSize={50} width="100%">
{({ index, style }) => <div style={style}>第 {index} 项</div>}
</FixedSizeList>;
常用库:react-window、react-virtual。
6. Context 性能优化
Context value 变化会导致所有消费组件重渲染,可以用 useMemo 稳定引用:
const value = useMemo(() => ({ theme, toggleTheme }), [theme]);
<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
或拆分读写 Context:
<ThemeStateContext.Provider value={theme}>
<ThemeDispatchContext.Provider value={toggleTheme}>
{children}
</ThemeDispatchContext.Provider>
</ThemeStateContext.Provider>
7. 图片/资源懒加载
<img src="large.jpg" loading="lazy" alt="图片" />
8. 避免在渲染中创建新对象/函数
// ❌ 每次渲染都创建新对象,导致子组件重渲染
<Child style={{ color: "red" }} />;
// ✅ 提到组件外或用 useMemo
const style = { color: "red" };
<Child style={style} />;
9. useTransition(React 18,并发优化)
把非紧急更新标记为低优先级,不阻塞用户交互:
const [isPending, startTransition] = useTransition();
startTransition(() => {
setList(heavyFilter(data)); // 低优先级更新
});
10. useDeferredValue(React 18)
延迟某个值的更新,类似防抖:
const deferredQuery = useDeferredValue(query);
const result = useMemo(() => {
return heavySearch(deferredQuery);
}, [deferredQuery]);
总结
| 方法 | 解决什么问题 |
|---|---|
React.memo |
避免子组件不必要渲染 |
useCallback |
稳定函数引用 |
useMemo |
缓存计算结果 |
| 状态下移 | 减少渲染范围 |
key |
优化列表 diff |
| 懒加载 | 减少首屏体积 |
| 虚拟列表 | 长列表性能 |
useTransition |
并发非紧急更新 |
最重要的原则:先测量再优化,不要过早优化。
