自学内容网 自学内容网

如何使用usememo和usecallback进行性能优化,什么时候使用usecallback,什么时候使用usememo

React useMemo 和 useCallback 性能优化总结以及使用场景

基本概念

useMemo

用于缓存计算结果,避免在每次渲染时重复进行昂贵的计算。

useCallback

用于缓存函数引用,避免在每次渲染时创建新的函数引用。

使用时机对比

useMemo 适用场景

  1. 复杂计算
function DataGrid({ items, filter }) {
  // 适用:复杂的数据处理
  const filteredItems = useMemo(() => {
    return items.filter(item => {
      return complexFilterLogic(item, filter);
    });
  }, [items, filter]);

  return <div>{filteredItems.map(item => <Item key={item.id} {...item} />)}</div>;
}
  1. 避免重复创建大对象
function ChartComponent({ data }) {
  // 适用:大数据结构转换
  const chartConfig = useMemo(() => ({
    data: transformData(data),
    options: {
      // 复杂的配置对象
      animations: { ... },
      scales: { ... },
      plugins: { ... }
    }
  }), [data]);

  return <Chart config={chartConfig} />;
}
  1. 引用相等性重要的场景
function ParentComponent() {
  // 适用:作为 props 传递的对象
  const memoizedValue = useMemo(() => ({
    id: 'unique',
    data: expensiveComputation()
  }), []);

  return <ChildComponent config={memoizedValue} />;
}

useCallback 适用场景

  1. 传递给子组件的回调函数
function ParentComponent() {
  const [items, setItems] = useState([]);
  
  // 适用:传递给子组件的事件处理函数
  const handleDelete = useCallback((id: string) => {
    setItems(prev => prev.filter(item => item.id !== id));
  }, []); // 依赖为空因为不依赖任何外部变量

  return <ItemList items={items} onDelete={handleDelete} />;
}
  1. 自定义 Hook 中返回的函数
function useSearch(initialQuery: string) {
  const [query, setQuery] = useState(initialQuery);
  
  // 适用:Hook 返回的函数
  const search = useCallback(async () => {
    const results = await api.search(query);
    return results;
  }, [query]);

  return { search, query, setQuery };
}
  1. 依赖于 props 或状态的事件处理
function UserActions({ userId, onSuccess }) {
  // 适用:依赖外部变量的回调
  const handleUpdate = useCallback(async (data) => {
    await api.updateUser(userId, data);
    onSuccess();
  }, [userId, onSuccess]);

  return <UserForm onSubmit={handleUpdate} />;
}

不需要使用的场景

不需要 useMemo

  1. 简单的计算
// ❌ 过度优化
const fullName = useMemo(() => 
  firstName + ' ' + lastName, 
  [firstName, lastName]
);

// ✅ 直接计算
const fullName = firstName + ' ' + lastName;
  1. 基本类型值
// ❌ 不必要
const count = useMemo(() => items.length, [items]);

// ✅ 直接使用
const count = items.length;

不需要 useCallback

  1. 组件内部使用的函数
// ❌ 不必要
const handleClick = useCallback(() => {
  console.log('clicked');
}, []);

// ✅ 直接定义
const handleClick = () => {
  console.log('clicked');
};
  1. 不会作为 props 传递的函数
// ❌ 过度优化
const formatDate = useCallback((date) => {
  return new Date(date).toLocaleDateString();
}, []);

// ✅ 直接定义或移到组件外
const formatDate = (date) => {
  return new Date(date).toLocaleDateString();
};

最佳实践

  1. 合理使用依赖数组
function SearchComponent({ onSearch }) {
  const [query, setQuery] = useState('');

  const handleSearch = useCallback(() => {
    onSearch(query);
  }, [query, onSearch]); // 包含所有依赖项
}
  1. 配合 React.memo 使用
const MemoizedChild = React.memo(function Child({ onAction }) {
  return <button onClick={onAction}>Click me</button>;
});

function Parent() {
  const handleAction = useCallback(() => {
    // 处理逻辑
  }, []); // 空依赖数组确保函数引用稳定

  return <MemoizedChild onAction={handleAction} />;
}
  1. 避免过度优化
function App() {
  // 只在真正需要的地方使用
  const expensiveValue = useMemo(() => 
    veryExpensiveOperation(), 
    [/* 相关依赖 */]
  );

  const criticalCallback = useCallback(() => 
    importantOperation(), 
    [/* 相关依赖 */]
  );
}

性能考虑

  1. 监控性能影响
  • 使用 React DevTools Profiler
  • 测量实际性能提升
  • 只在有明显收益时使用
  1. 权衡成本
  • 考虑内存使用
  • 评估缓存开销
  • 注意依赖数组的大小
  1. 优化策略
  • 优先考虑架构优化
  • 合理拆分组件
  • 使用适当的数据结构

原文地址:https://blog.csdn.net/qq_34645412/article/details/145292371

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!