什么❓问我React性能优化,问对人了

475 阅读3分钟

前言:为什么需要优化?

React虽然很快,但不当的使用方式会让你的应用变得卡顿。想象一下用户对着转圈圈的页面干瞪眼的样子——这可不是我们想要的体验。

跟着这篇指南,4分钟让你掌握React性能优化的核心技巧!


一、函数组件三叉戟🔱

1. React.memo - 记住组件

const MyComponent = React.memo(({ data }) => {
  return <div>{data}</div>
})

就像给组件装了"记忆芯片",只有props真的变了才会重新渲染。

// React.memo通过浅比较,比较props的变化,决定是否重新渲染。
// 只有当 props的引用或者值改变才触发重渲染。
const UserProfile = React.memo(({ user, settings }) => {
  return (
    <div>
      <Avatar url={user.avatar} />
      <ThemePicker theme={settings.theme} />
    </div>
  )
})

在项目中,用到的地方,比如说:

  • 纯展示的(头像、卡片等)
  • 静态子组件(它的父组件需要频繁更新的)
  • 复杂props的组件

2. useMemo - 记住计算结果

const result = useMemo(() => expensiveCalculation(input), [input])

把昂贵的计算结果缓存起来,避免每次渲染都重新计算。

比如说,做大数据量的排序:

// 大数据量排序
const sortedList = useMemo(() => {
  return bigData.sort((a, b) => a.value - b.value)
}, [bigData])

// 复杂对象转换
const chartOptions = useMemo(() => ({
  title: { text: dataset.name },
  series: dataset.points.map(...)
}), [dataset])

务必牢记:

  • 计算成本 > 缓存成本,用它。
  • 依赖要精准。
  • 不要哪里都用,简单计算的就不要用它了。

3. useCallback - 记住函数

const handleClick = useCallback(() => {
  doSomething(id)
}, [id])

防止函数被重复创建,特别适合传给子组件的回调函数。

// 父组件
const Parent = () => {
  const handleSelect = useCallback((id) => {
    setSelectedId(id)
  }, [])

  return <Child onSelect={handleSelect} />
}

// 子组件 与React.memo配合使用效果最佳
const Child = React.memo(({ onSelect }) => {
  return <Button onClick={onSelect} />
})

注意:避免在useCallback内部创建新对象。

这三个就像"性能三剑客",配合使用效果更佳!


二、类组件两大绝招

1. PureComponent

class MyComp extends React.PureComponent {
  render() {
    return <div>{this.props.data}</div>
  }
}

自动帮你做浅比较,相当于自带shouldComponentUpdate。

2. shouldComponentUpdate

shouldComponentUpdate(nextProps) {
  return nextProps.id !== this.props.id
}

手动控制更新条件,适合复杂比较场景。

定律:(1)、优先用PureComponent;(2)、可以搭配immutable.js一起用。


三、通用优化技巧

1. 列表渲染要加key

{items.map(item => (
  <Item key={item.id} />  // ✅ 用唯一id
  // <Item key={index} />  ❌ 别用索引!
))}

长列表优化,可以适当地恰当地用库来做,比如说react-window(推荐),react-virtualized(功能全面)。图片的话,用Intersection Observer做懒加载。数据实在太大,10万以上的话结合一下Web Worker去开一个异步线程去处理吧,不要堵塞住。

2. 懒加载大组件

const HeavyComp = React.lazy(() => import('./HeavyComp'))

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <HeavyComp />
    </Suspense>
  )
}

3. 避免不必要的div嵌套

// 🚩 用不到的div就尽量去除,能去除就出去
return (
  <div>
    <div>
      <Child />
    </div>
  </div>
)

// ✅
return <Child />

四、常见误区

  1. 过度优化:不是所有组件都需要memo
  2. 错误使用key:用index当key等于没优化
  3. 滥用useMemo:简单计算不需要缓存
  4. 忽略开发工具:React DevTools能帮你找出性能瓶颈

记住:先写功能,再测性能,最后优化!永远不要过早优化,过早优化是万恶之源!


五、性能检测工具

  1. React DevTools的Profiler
  2. Chrome的Performance面板
  3. 安装why-did-you-render:
npm install @welldone-software/why-did-you-render

总结:优化

  1. 用React.memo包裹纯展示组件
  2. 复杂计算用useMemo缓存
  3. 回调函数用useCallback包裹
  4. 列表必须加稳定的key
  5. 大组件使用懒加载
  6. 定期用性能工具检测

优化就像给代码做健身,适当的"锻炼"能让你的应用跑得更快。但记住——过度优化反而会让代码难以维护,要适当,拿捏好度。