大家好,我是小杨,一个写了6年前端的老油条。今天咱们聊聊React性能优化------这个话题看似简单,但很多项目其实都藏着不少性能隐患。
你有没有遇到过这些情况?
- 页面越写越卡,交互变得迟钝
- 列表滚动时疯狂掉帧,用户体验直线下降
- 明明数据没变,组件却莫名其妙重新渲染
如果你中招了,那这篇就是为你准备的。咱们不扯虚的,直接上干货!
1. 为什么React会变慢?
React的核心是虚拟DOM(Virtual DOM) ,它通过Diff算法比对变化,然后最小化DOM操作。但如果你滥用setState、不合理的组件设计,或者依赖项没处理好,React就会做很多不必要的计算,导致性能下降。
2. 实战优化技巧
✅ 技巧1:避免不必要的重新渲染(React.memo / PureComponent)
如果你的组件接收的props没变 ,但依然频繁渲染,可以用React.memo(函数组件)或PureComponent(类组件)来优化:
            
            
              jsx
              
              
            
          
          // 优化前:每次父组件更新,Child都会重新渲染
const Child = ({ data }) => {
  console.log("Child渲染了!");
  return <div>{data}</div>;
};
// 优化后:只有data变化时才重新渲染
const MemoizedChild = React.memo(({ data }) => {
  console.log("MemoizedChild渲染了!");
  return <div>{data}</div>;
});适用场景:
- 纯展示型组件
- 频繁更新的父组件下的子组件
✅ 技巧2:useCallback & useMemo 缓存函数和计算值
问题 :每次父组件渲染,内联函数都会重新创建,导致子组件(即使用了React.memo)也重新渲染。
            
            
              jsx
              
              
            
          
          // ❌ 每次渲染都会创建新的handleClick
const Parent = () => {
  const handleClick = () => {
    console.log("点击了我");
  };
  return <Child onClick={handleClick} />;
};
// ✅ 用useCallback缓存函数
const Parent = () => {
  const handleClick = useCallback(() => {
    console.log("点击了我");
  }, []); // 依赖项为空,函数只创建一次
  return <Child onClick={handleClick} />;
};useMemo 类似,但用于缓存计算结果:
            
            
              jsx
              
              
            
          
          const expensiveValue = useMemo(() => {
  return computeExpensiveValue(a, b); // 只有a或b变化时才重新计算
}, [a, b]);✅ 技巧3:列表渲染用key,但别用index!
错误示范:
            
            
              jsx
              
              
            
          
          {items.map((item, index) => (
  <Item key={index} {...item} /> // ❌ 用index当key,性能杀手!
))}正确做法:
            
            
              jsx
              
              
            
          
          {items.map((item) => (
  <Item key={item.id} {...item} /> // ✅ 用唯一ID
))}为什么?
- index作为key 会导致React在列表变动时错误复用DOM,可能引发渲染错乱 或性能下降。
- 唯一ID (如item.id)能帮助React精准识别列表项,减少不必要的DOM操作。
✅ 技巧4:懒加载(React.lazy + Suspense)
如果你的应用很大,首屏加载慢,可以用代码分割(Code Splitting) :
            
            
              jsx
              
              
            
          
          const HeavyComponent = React.lazy(() => import("./HeavyComponent"));
function App() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}这样,HeavyComponent 只会在需要时加载,减少首屏负担。
✅ 技巧5:避免在render里做高开销计算
反例:
            
            
              jsx
              
              
            
          
          function Component({ list }) {
  const filteredList = list.filter(item => item.isActive); // 每次渲染都计算
  return <List items={filteredList} />;
}优化后:
            
            
              jsx
              
              
            
          
          function Component({ list }) {
  const filteredList = useMemo(() => {
    return list.filter(item => item.isActive); // 只有list变化时才计算
  }, [list]);
  return <List items={filteredList} />;
}3. 进阶优化:useReducer替代useState
如果你的组件有复杂的状态逻辑 ,useState可能会导致大量重新渲染。这时可以试试useReducer:
            
            
              jsx
              
              
            
          
          const initialState = { count: 0 };
function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    default:
      return state;
  }
}
function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <button onClick={() => dispatch({ type: "increment" })}>
      点了{state.count}次
    </button>
  );
}优点:
- 更适合管理复杂状态
- 减少不必要的setState调用
4. 终极武器:React Profiler
如果你不确定哪里卡顿,可以用React DevTools的Profiler:
- 打开Chrome DevTools → React → Profiler
- 点击录制,操作页面
- 分析哪些组件渲染次数过多
总结
React性能优化不是一蹴而就的,但掌握这些技巧能大幅提升应用流畅度:
- React.memo/- PureComponent→ 避免不必要的渲染
- useCallback&- useMemo→ 缓存函数和计算值
- 列表key用唯一ID → 别用index!
- 懒加载(React.lazy) → 减少首屏加载时间
- useReducer管理复杂状态 → 减少- setState触发
- React Profiler定位瓶颈 → 精准优化
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!
