React 中hooks之 React useCallback使用方法总结

打印 上一主题 下一主题

主题 1001|帖子 1001|积分 3003

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1. useCallback 底子概念

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

  1. const memoizedCallback = useCallback(
  2.   () => {
  3.     doSomething(a, b);
  4.   },
  5.   [a, b], // 依赖项数组
  6. );
复制代码
同样的当依赖项省略时组件重新渲染都会实行,当依赖项为空数组的时候只有组件初始化的时候会实行一次,数组里有依赖项的时候依赖项发生变化的时候都会缓存一次
1.2 与平凡函数的区别

  1. function ParentComponent() {
  2.   const [count, setCount] = useState(0);
  3.   // ❌ 每次渲染都会创建新的函数实例
  4.   const handleClick = () => {
  5.     console.log('Clicked');
  6.   };
  7.   // ✅ 函数实例会被记忆,只在依赖项变化时更新
  8.   const handleClickMemoized = useCallback(() => {
  9.     console.log('Clicked');
  10.   }, []); // 空依赖数组,函数永远不会改变
  11.   return <ChildComponent onClick={handleClickMemoized} />;
  12. }
复制代码
2. useCallback 配合 React.memo 使用

2.1 基本示例

  1. // 子组件使用 React.memo 优化
  2. const ChildComponent = React.memo(function ChildComponent({ onClick }) {
  3.   console.log("ChildComponent rendered");
  4.   return <button onClick={onClick}>Click me</button>;
  5. });
  6. // 父组件使用 useCallback
  7. function ParentComponent() {
  8.   const [count, setCount] = useState(0);
  9.   const [text, setText] = useState("");
  10.   // 使用 useCallback 记忆回调函数
  11.   const handleClick = useCallback(() => {
  12.     setCount(c => c + 1);
  13.   }, []); // 空依赖数组,因为不依赖任何值
  14.   return (
  15.     <div>
  16.       <input value={text} onChange={e => setText(e.target.value)} />
  17.       <p>Count: {count}</p>
  18.       <ChildComponent onClick={handleClick} />
  19.     </div>
  20.   );
  21. }
复制代码
2.2 带有依赖项的示例

  1. function SearchComponent({ onSearch }) {
  2.   const [searchTerm, setSearchTerm] = useState("");
  3.   const [searchHistory, setSearchHistory] = useState([]);
  4.   // 使用 useCallback 记忆搜索函数
  5.   const handleSearch = useCallback(() => {
  6.     if (searchTerm.trim()) {
  7.       onSearch(searchTerm);
  8.       setSearchHistory(prev => [...prev, searchTerm]);
  9.     }
  10.   }, [searchTerm, onSearch]); // 依赖 searchTerm 和 onSearch
  11.   return (
  12.     <div>
  13.       <input
  14.         value={searchTerm}
  15.         onChange={e => setSearchTerm(e.target.value)}
  16.       />
  17.       <SearchButton onClick={handleSearch} />
  18.       <SearchHistory items={searchHistory} />
  19.     </div>
  20.   );
  21. }
  22. // 优化的子组件
  23. const SearchButton = React.memo(function SearchButton({ onClick }) {
  24.   console.log("SearchButton rendered");
  25.   return <button onClick={onClick}>搜索</button>;
  26. });
  27. const SearchHistory = React.memo(function SearchHistory({ items }) {
  28.   return (
  29.     <ul>
  30.       {items.map((item, index) => (
  31.         <li key={index}>{item}</li>
  32.       ))}
  33.     </ul>
  34.   );
  35. });
复制代码
3. 实际应用场景

3.1 表单处理

  1. function ComplexForm() {
  2.   const [formData, setFormData] = useState({
  3.     name: '',
  4.     email: '',
  5.     message: ''
  6.   });
  7.   // 记忆表单字段更新函数
  8.   const handleFieldChange = useCallback((fieldName) => (event) => {
  9.     setFormData(prev => ({
  10.       ...prev,
  11.       [fieldName]: event.target.value
  12.     }));
  13.   }, []); // 不需要依赖项,因为使用了函数式更新
  14.   return (
  15.     <form>
  16.       <FormField
  17.         label="Name"
  18.         value={formData.name}
  19.         onChange={handleFieldChange('name')}
  20.       />
  21.       <FormField
  22.         label="Email"
  23.         value={formData.email}
  24.         onChange={handleFieldChange('email')}
  25.       />
  26.       <FormField
  27.         label="Message"
  28.         value={formData.message}
  29.         onChange={handleFieldChange('message')}
  30.       />
  31.     </form>
  32.   );
  33. }
  34. const FormField = React.memo(function FormField({ label, value, onChange }) {
  35.   console.log(`${label} field rendered`);
  36.   return (
  37.     <div>
  38.       <label>{label}</label>
  39.       <input value={value} onChange={onChange} />
  40.     </div>
  41.   );
  42. });
复制代码
3.2 列表渲染优化

  1. function TodoList() {
  2.   const [todos, setTodos] = useState([]);
  3.   // 记忆添加任务函数
  4.   const handleAdd = useCallback((text) => {
  5.     setTodos(prev => [...prev, { id: Date.now(), text, completed: false }]);
  6.   }, []);
  7.   // 记忆切换完成状态函数
  8.   const handleToggle = useCallback((id) => {
  9.     setTodos(prev =>
  10.       prev.map(todo =>
  11.         todo.id === id ? { ...todo, completed: !todo.completed } : todo
  12.       )
  13.     );
  14.   }, []);
  15.   // 记忆删除函数
  16.   const handleDelete = useCallback((id) => {
  17.     setTodos(prev => prev.filter(todo => todo.id !== id));
  18.   }, []);
  19.   return (
  20.     <div>
  21.       <AddTodo onAdd={handleAdd} />
  22.       {todos.map(todo => (
  23.         <TodoItem
  24.           key={todo.id}
  25.           todo={todo}
  26.           onToggle={handleToggle}
  27.           onDelete={handleDelete}
  28.         />
  29.       ))}
  30.     </div>
  31.   );
  32. }
  33. const TodoItem = React.memo(function TodoItem({ todo, onToggle, onDelete }) {
  34.   return (
  35.     <div>
  36.       <input
  37.         type="checkbox"
  38.         checked={todo.completed}
  39.         onChange={() => onToggle(todo.id)}
  40.       />
  41.       <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
  42.         {todo.text}
  43.       </span>
  44.       <button onClick={() => onDelete(todo.id)}>删除</button>
  45.     </div>
  46.   );
  47. });
复制代码
4. 性能优化最佳实践

4.1 合理使用依赖项

  1. function UserProfile({ userId, onUpdate }) {
  2.   // ✅ 只在 userId 或 onUpdate 变化时更新
  3.   const handleUpdate = useCallback(() => {
  4.     onUpdate(userId);
  5.   }, [userId, onUpdate]);
  6.   // ❌ 不必要的依赖项
  7.   const handleClick = useCallback(() => {
  8.     console.log('Clicked');
  9.   }, [userId]); // userId 不需要作为依赖项
  10. }
复制代码
4.2 避免过分优化

  1. // ❌ 简单组件不需要使用 useCallback
  2. function SimpleButton({ onClick }) {
  3.   return <button onClick={onClick}>Click me</button>;
  4. }
  5. // ✅ 复杂组件或频繁重渲染的组件使用 useCallback
  6. const ComplexComponent = React.memo(function ComplexComponent({ onAction }) {
  7.   // 复杂的渲染逻辑
  8.   return (
  9.     // ...
  10.   );
  11. });
复制代码
5. useCallback 与其他 Hooks 配合

5.1 配合 useEffect 使用

  1. function DataFetcher({ query }) {
  2.   const [data, setData] = useState(null);
  3.   // 记忆获取数据的函数
  4.   const fetchData = useCallback(async () => {
  5.     const response = await fetch(`/api/search?q=${query}`);
  6.     const result = await response.json();
  7.     setData(result);
  8.   }, [query]);
  9.   // 在 effect 中使用记忆的函数
  10.   useEffect(() => {
  11.     fetchData();
  12.   }, [fetchData]); // fetchData 作为依赖项
  13.   return <div>{/* 渲染数据 */}</div>;
  14. }
复制代码
5.2 配合 useMemo 使用

  1. function DataProcessor({ data, onProcess }) {
  2.   // 记忆处理函数
  3.   const processData = useCallback((item) => {
  4.     // 复杂的数据处理逻辑
  5.     return someExpensiveOperation(item);
  6.   }, []);
  7.   // 使用记忆的函数处理数据
  8.   const processedData = useMemo(() => {
  9.     return data.map(processData);
  10.   }, [data, processData]);
  11.   return (
  12.     <div>
  13.       {processedData.map(item => (
  14.         <ProcessedItem
  15.           key={item.id}
  16.           item={item}
  17.           onProcess={onProcess}
  18.         />
  19.       ))}
  20.     </div>
  21.   );
  22. }
复制代码
6. 注意事项


  • 避免过分使用

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

  • 精确设置依赖项

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

  • 配合 React.memo 使用

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

  • 思量使用场景

    • 频仍重渲染的组件
    • 复杂的盘算或操作
    • 通报给多个子组件的回调

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

万有斥力

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表