React useCallback使用方法详解

 更新时间:2025年01月21日 08:21:42   作者:前端涂涂  
useCallback 是 React 的一个 Hook,用于记忆函数定义,避免在每次渲染时创建新的函数实例,本文主要来介绍一下它的具体用法,需要的可以参考一下

1. useCallback 基础概念

useCallback 是 React 的一个 Hook,用于记忆函数定义,避免在每次渲染时创建新的函数实例。它在需要将回调函数传递给经过优化的子组件时特别有用。 当state变化的时候引起组件重新渲染执行会导致某个方法被反复创建增加内存负担,这个时候可以使用useCallback将该函数进行缓存,只创建一次

1.1 基本语法

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b], // 依赖项数组
);

同样的当依赖项省略时组件重新渲染都会执行,当依赖项为空数组的时候只有组件初始化的时候会执行一次,数组里有依赖项的时候依赖项发生变化的时候都会缓存一次

1.2 与普通函数的区别

function ParentComponent() {
  const [count, setCount] = useState(0);

  // ❌ 每次渲染都会创建新的函数实例
  const handleClick = () => {
    console.log('Clicked');
  };

  // ✅ 函数实例会被记忆,只在依赖项变化时更新
  const handleClickMemoized = useCallback(() => {
    console.log('Clicked');
  }, []); // 空依赖数组,函数永远不会改变

  return <ChildComponent onClick={handleClickMemoized} />;
}

2. useCallback 配合 React.memo 使用

2.1 基本示例

// 子组件使用 React.memo 优化
const ChildComponent = React.memo(function ChildComponent({ onClick }) {
  console.log("ChildComponent rendered");
  return <button onClick={onClick}>Click me</button>;
});

// 父组件使用 useCallback
function ParentComponent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");

  // 使用 useCallback 记忆回调函数
  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, []); // 空依赖数组,因为不依赖任何值

  return (
    <div>
      <input value={text} onChange={e => setText(e.target.value)} />
      <p>Count: {count}</p>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

2.2 带有依赖项的示例

function SearchComponent({ onSearch }) {
  const [searchTerm, setSearchTerm] = useState("");
  const [searchHistory, setSearchHistory] = useState([]);

  // 使用 useCallback 记忆搜索函数
  const handleSearch = useCallback(() => {
    if (searchTerm.trim()) {
      onSearch(searchTerm);
      setSearchHistory(prev => [...prev, searchTerm]);
    }
  }, [searchTerm, onSearch]); // 依赖 searchTerm 和 onSearch

  return (
    <div>
      <input
        value={searchTerm}
        onChange={e => setSearchTerm(e.target.value)}
      />
      <SearchButton onClick={handleSearch} />
      <SearchHistory items={searchHistory} />
    </div>
  );
}

// 优化的子组件
const SearchButton = React.memo(function SearchButton({ onClick }) {
  console.log("SearchButton rendered");
  return <button onClick={onClick}>搜索</button>;
});

const SearchHistory = React.memo(function SearchHistory({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
});

3. 实际应用场景

3.1 表单处理

function ComplexForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });

  // 记忆表单字段更新函数
  const handleFieldChange = useCallback((fieldName) => (event) => {
    setFormData(prev => ({
      ...prev,
      [fieldName]: event.target.value
    }));
  }, []); // 不需要依赖项,因为使用了函数式更新

  return (
    <form>
      <FormField
        label="Name"
        value={formData.name}
        onChange={handleFieldChange('name')}
      />
      <FormField
        label="Email"
        value={formData.email}
        onChange={handleFieldChange('email')}
      />
      <FormField
        label="Message"
        value={formData.message}
        onChange={handleFieldChange('message')}
      />
    </form>
  );
}

const FormField = React.memo(function FormField({ label, value, onChange }) {
  console.log(`${label} field rendered`);
  return (
    <div>
      <label>{label}</label>
      <input value={value} onChange={onChange} />
    </div>
  );
});

3.2 列表渲染优化

function TodoList() {
  const [todos, setTodos] = useState([]);

  // 记忆添加任务函数
  const handleAdd = useCallback((text) => {
    setTodos(prev => [...prev, { id: Date.now(), text, completed: false }]);
  }, []);

  // 记忆切换完成状态函数
  const handleToggle = useCallback((id) => {
    setTodos(prev =>
      prev.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  }, []);

  // 记忆删除函数
  const handleDelete = useCallback((id) => {
    setTodos(prev => prev.filter(todo => todo.id !== id));
  }, []);

  return (
    <div>
      <AddTodo onAdd={handleAdd} />
      {todos.map(todo => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={handleToggle}
          onDelete={handleDelete}
        />
      ))}
    </div>
  );
}

const TodoItem = React.memo(function TodoItem({ todo, onToggle, onDelete }) {
  return (
    <div>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => onToggle(todo.id)}
      />
      <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
        {todo.text}
      </span>
      <button onClick={() => onDelete(todo.id)}>删除</button>
    </div>
  );
});

4. 性能优化最佳实践

4.1 合理使用依赖项

function UserProfile({ userId, onUpdate }) {
  // ✅ 只在 userId 或 onUpdate 变化时更新
  const handleUpdate = useCallback(() => {
    onUpdate(userId);
  }, [userId, onUpdate]);

  // ❌ 不必要的依赖项
  const handleClick = useCallback(() => {
    console.log('Clicked');
  }, [userId]); // userId 不需要作为依赖项
}

4.2 避免过度优化

// ❌ 简单组件不需要使用 useCallback
function SimpleButton({ onClick }) {
  return <button onClick={onClick}>Click me</button>;
}

// ✅ 复杂组件或频繁重渲染的组件使用 useCallback
const ComplexComponent = React.memo(function ComplexComponent({ onAction }) {
  // 复杂的渲染逻辑
  return (
    // ...
  );
});

5. useCallback 与其他 Hooks 配合

5.1 配合 useEffect 使用

function DataFetcher({ query }) {
  const [data, setData] = useState(null);

  // 记忆获取数据的函数
  const fetchData = useCallback(async () => {
    const response = await fetch(`/api/search?q=${query}`);
    const result = await response.json();
    setData(result);
  }, [query]);

  // 在 effect 中使用记忆的函数
  useEffect(() => {
    fetchData();
  }, [fetchData]); // fetchData 作为依赖项

  return <div>{/* 渲染数据 */}</div>;
}

5.2 配合 useMemo 使用

function DataProcessor({ data, onProcess }) {
  // 记忆处理函数
  const processData = useCallback((item) => {
    // 复杂的数据处理逻辑
    return someExpensiveOperation(item);
  }, []);

  // 使用记忆的函数处理数据
  const processedData = useMemo(() => {
    return data.map(processData);
  }, [data, processData]);

  return (
    <div>
      {processedData.map(item => (
        <ProcessedItem
          key={item.id}
          item={item}
          onProcess={onProcess}
        />
      ))}
    </div>
  );
}

6. 注意事项

避免过度使用

  • 只在性能确实受影响时使用
  • 简单组件和回调不需要使用 useCallback

正确设置依赖项

  • 包含所有回调中使用的变量
  • 避免不必要的依赖项

配合 React.memo 使用

  • 单独使用 useCallback 可能无法带来性能提升
  • 需要配合 React.memo 等优化手段

考虑使用场景

  • 频繁重渲染的组件
  • 复杂的计算或操作
  • 传递给多个子组件的回调

通过合理使用 useCallback 和 React.memo,我们可以有效优化 React 应用的性能。但要记住,过度优化可能会适得其反,应该在实际需要时才进行优化。

到此这篇关于React useCallback使用方法详解的文章就介绍到这了,更多相关React useCallback内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • react中函数式组件React Hooks详解

    react中函数式组件React Hooks详解

    这篇文章主要介绍了react中函数式组件React Hooks的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • React中useMemo与useCallback区别以及各自解决什么性能问题、依赖陷阱详解

    React中useMemo与useCallback区别以及各自解决什么性能问题、依赖陷阱详解

    useCallback和useMemo是一样的东西,只是入参有所不同,这篇文章主要介绍了React中useMemo与useCallback区别以及各自解决什么性能问题、依赖陷阱的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-05-05
  • React-Native中props具体使用详解

    React-Native中props具体使用详解

    本篇文章主要介绍了React-Native中props具体使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • React学习笔记之列表渲染示例详解

    React学习笔记之列表渲染示例详解

    最近在学习React,学习到了列表渲染这一块,发现网上这方面的资料较少,所以自己来总结下,下面这篇文章主要给大家介绍了关于React学习笔记之列表渲染的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-08-08
  • 如何利用React实现图片识别App

    如何利用React实现图片识别App

    图片识别这个功能在很多app中都有,下面这篇文章主要给大家介绍了关于如何利用React实现图片识别App的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-01-01
  • React Virtual DOM前端框架全面分析

    React Virtual DOM前端框架全面分析

    这篇文章主要为大家介绍了React Virtual DOM前端框架全面分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • React SSR架构Stream Rendering与Suspense for Data Fetching

    React SSR架构Stream Rendering与Suspense for Data Fetching

    这篇文章主要为大家介绍了React SSR架构Stream Rendering与Suspense for Data Fetching解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • React使用React.lazy和Suspense实现组件懒加载

    React使用React.lazy和Suspense实现组件懒加载

    React 提供了 React.lazy 和 Suspense 这两个好东西,能让我们实现组件的懒加载,下面就跟随小编一起来了解一下如何使用它们实现懒加载的具体步骤吧
    2025-03-03
  • React中Suspense及lazy()懒加载及代码分割原理和使用方式

    React中Suspense及lazy()懒加载及代码分割原理和使用方式

    这篇文章主要介绍了React中Suspense及lazy()懒加载及代码分割原理和使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • React中合成事件的实现

    React中合成事件的实现

    React合成事件是对浏览器原生事件的封装,提供跨浏览器一致性API,采用事件委托机制提升性能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-09-09

最新评论