【前端】【React】性能优化三件套useCallback,useMemo,React.memo

发布于:2025-04-11 ⋅ 阅读:(471) ⋅ 点赞:(0)

一、总览:性能优化三件套

  • useCallback(fn, deps)缓存函数,避免每次渲染都新建函数。
  • useMemo(fn, deps)缓存值(计算结果),避免重复执行计算。
  • React.memo(Component)缓存组件的渲染结果,避免 props 没变却重复渲染。

三者搭配使用,在中大型组件中可显著优化性能,减少重复渲染。


二、逐个详解

(一)useCallback —— 缓存函数引用

  • (1) 每次组件渲染时函数都会重新创建,导致引用变了。
  • (2) 使用场景:
    • 给子组件传递函数 props 时避免子组件重复渲染。
    • 函数作为依赖传入 useEffect / useMemo
  • (3) 使用方式:
const handleClick = useCallback(() => {
  console.log("Clicked");
}, []);
  • (4) 注意事项:
    • 依赖项变化时函数才会更新。
    • 类似 useMemo(() => fn, deps)

(二)useMemo —— 缓存计算结果

  • (1) 每次组件渲染时如果存在复杂计算,可能导致性能问题。
  • (2) 使用场景:
    • 依赖变量变化时才重新计算;
    • 缓存对象、数组等引用类型的值。
  • (3) 使用方式:
const result = useMemo(() => heavyComputation(data), [data]);
  • (4) 注意事项:
    • 不要滥用;对性能无益时反而增加复杂性。
    • 常用于防止因对象/数组引用变化导致组件重新渲染。

(三)React.memo —— 缓存组件渲染结果

  • (1) 是一个高阶组件,用于函数组件。
  • (2) 默认只进行浅层比较,如果 props 没变,则跳过渲染。
  • (3) 使用方式:
const MyComponent = React.memo((props) => {
  return <div>{props.text}</div>;
});
  • (4) 使用场景:
    • 子组件 props 不变时,避免不必要的渲染。
    • 搭配 useCallback/useMemo 使用更有效。
  • (5) 可选第二参数自定义比较逻辑:
React.memo(Component, (prevProps, nextProps) => {
  return prevProps.id === nextProps.id;
});

三、组合使用示例

import React, { useState, useMemo, useCallback } from 'react';

const List = React.memo(({ items, onClickItem }) => {
  console.log("List rendered");
  return (
    <ul>
      {items.map(item => (
        <li key={item.id} onClick={() => onClickItem(item)}>
          {item.name}
        </li>
      ))}
    </ul>
  );
});

const App = () => {
  const [count, setCount] = useState(0);

  const items = useMemo(() => [
    { id: 1, name: "Apple" },
    { id: 2, name: "Banana" },
  ], []);

  const handleClick = useCallback((item) => {
    console.log("Clicked:", item.name);
  }, []);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Count: {count}</button>
      <List items={items} onClickItem={handleClick} />
    </div>
  );
};

分析说明:

  • ListReact.memo 包裹,只有 itemsonClickItem 改变才会重新渲染。
  • itemsuseMemo 缓存,防止数组地址变化。
  • handleClickuseCallback 缓存函数,防止函数引用变化。

四、注意事项与总结

  • ✅ 使用这些 Hook 是性能优化手段,不是每个项目都需要用。
  • ❌ 滥用会增加代码复杂度,尤其在小组件中意义不大。
  • 👀 推荐在以下情况使用:
    • 子组件使用了 React.memo
    • 函数或对象在依赖中频繁触发更新;
    • 存在大型列表或复杂计算逻辑;
    • 性能瓶颈场景下的精细优化。