React——useCallback

打印 上一主题 下一主题

主题 874|帖子 874|积分 2626

一、定义:

useCallback是一个允许你在多次渲染中缓存函数的 React Hook。它返回一个记忆化的回调函数,只有在依赖项改变时才会更新。这有助于避免在每次渲染时都创建新的函数实例,特殊是在将回调函数通报给子组件时。
二、情势:

  1. useCallback(function,dependencies)
复制代码
参数:

function

1、定义:想要缓存的函数
2、特点:


  • 可以担当任何参数并返回任何值
  • React只会把这个函数返回给你,而不是直接调用!!(由你本身决定何时调用)
  • 进行下一次渲染时,dependencies没有变革,则funtion返回相同的函数;如有变革,React将新传入的函数缓存以便后续利用
dependencies

1、定义:有关是否更新function的全部响应值的一个列表
2、特点:


  • 响应式值包罗 props、state,和全部在你组件内部直接声明的变量和函数。
  • 依赖列表必须具有确切数量的项,并且必须像 [dep1, dep2, dep3] 这样编写
  • React 利用 Object.is 比较每一个依赖和它的之前的值。
返回值:

在初次渲染时,useCallback 返回你已经传入的 function 函数
在之后的渲染中, 如果依赖没有改变,useCallback 返回上一次渲染中缓存的 function 函数;否则返回这一次渲染传入的 function。
三、注意点

1、useCallback 是一个 Hook,所以应该在 组件的顶层 或自定义 Hook 中调用(不应在循环或者条件语句中调用它)
缘故原由:这样做是为了确保 Hook 的调用顺序在每次渲染中是一致的。React 利用这个顺序来跟踪每个 Hook 的状态和效果。
应对步伐:如果你必要在循环或者条件语句中调用它,正确的办法应该是新建一个组件,并将state移入此中
2、useCallback 是一个有用的性能优化工具,但在某些情况下(尤其是在开发和特定的生产场景中),其缓存可能会被抛弃
四、用法

1、跳过组件的重新渲染

配景:默认情况下,当一个组件重新渲染时, React 将递归渲染它的全部子组件,有时会导致重新渲染的很慢
初始解决:

将子组件包裹在memo中,例:
  1. import { memo } from 'react';
  2. const ShippingForm = memo(function ShippingForm({ onSubmit }) {
  3.   // ...
  4. });
复制代码
好处:如果prop与上一次渲染时相同,这个子组件将跳过重新渲染
不敷:在 JavaScript 中,function () {} 或者 () => {} 总是会天生差别的函数,所以因某个变量更改导致组件重新渲染时,那么作为prop传入子组件的函数每次都不一样时,这也导致了memo对性能的优化永远不会见效
优化解决:

思路:将作为prop传入的子函数通报给useCallback,这样可以确保它在多次重新渲染之间是相同的函数(除非是依赖项发生变革它才会变革),也就能让memo知道这时该prop与上次没有变革,子组件也就不会重新渲染。
注:useCallback只应用作性能优化,除非出于某种特定缘故原由,否则不必将一个函数包裹在 useCallback 中
useCallback应用场景:



  • 将其作为 props 通报给包装在 [memo] 中的组件。如果 props 未更改,则盼望跳过重新渲染。缓存允许组件仅在依赖项更改时重新渲染。
  • 通报的函数可能作为某些 Hook 的依赖。比如,另一个包裹在 useCallback 中的函数依赖于它,或者依赖于 useEffect 中的函数。
注意:useCallback不会阻止创建函数,你总是在创建一个函数(这很好!),但是如果没有任何东西改变,React会忽略它并返回缓存的函数
2、从记忆回调中更新state

配景:想实现在useCallback回调中基于之前的state来更新state
例:
做法一:指定依赖项

  1. function TodoList() {
  2.   const [todos, setTodos] = useState([]);
  3.   const handleAddTodo = useCallback((text) => {
  4.     const newTodo = { id: nextId++, text };
  5.     setTodos([...todos, newTodo]);
  6.   }, [todos]);
复制代码
做法二:利用updater function

  1. function TodoList() {
  2.   const [todos, setTodos] = useState([]);
  3.   const handleAddTodo = useCallback((text) => {
  4.     const newTodo = { id: nextId++, text };
  5.     setTodos(todos => [...todos, newTodo]);
  6.   }, []); // ✅ 不需要 todos 依赖项
复制代码
在 React 中,updater function 是一种用于更新组件状态的函数,它允许你基于当前状态盘算下一个状态,而不必要将当前状态作为依赖项传useCallback。
好处:


  • 可以资助减少依赖项的数量,从而避免不必要的重新渲染。
  • 可以确保在状态更新时始终利用最新的状态值。尤其在处理异步操作时,直接引用 状态值 可能会导致不一致的效果。
3、防止频仍触发Effect

配景:想要在Effect内部调用函数
例:聊天室的案例
[code]function ChatRoom({ roomId }) {
  const [message, setMessage] = useState('');

  function createOptions() {
    return {
      serverUrl: 'https://localhost:1234',
      roomId: roomId
    };

  }
useEffect(() => {
    const options = createOptions();
    const connection = createConnection(options);
    connection.connect();
    return () => connection.disconnect();

  }, [createOptions]); //
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

东湖之滨

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表