useMemo用于记住值,减少重新渲染组件所需的时间。

useCallback用于记住函数,避免函数不必要的重新创建,进而防止组件的重新渲染,适用于父组件需要将回调函数作为props传递给子组件的情况

它的作用到底是什么?useCallback的作用其实是用来避免子组件不必要的reRender:

场景1、举例子组件接收回调函数作为 props
父组件引入子组件:

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

    function MyComponent() {

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

   const handleClick = useCallback(

     () => { setCount(count + 1);

     }, [count]);

  return (

      <div> <p>Count: {count}</p> //当父组件的state发生变化时,父组件会重新渲染(render)

       <button clickFn={handleClick}>Increment</button> //父组件将handleClick方法作为参数props传递给子组件

   </div>

 ); }

使用了useCallback,handleClick函数会被记忆,只要count没有改变,React 就会重用之前的函数实例(函数引用),这样可以避免在每次渲染时都创建一个新的函数,提高性能。

当count发生变化时,重新创建名为handleClick函数实例,并通过props传递给子组件吗,就会触发子组件的重新渲染,总之,handleClick函数发生了变化,props也会发生变化,子组件就会重新渲染。

注意,必须要用React.memo把子组件包起来才有用,否则子组件还是会reRender

2、函数作为依赖项被加入到一个useEffect

import React, { useEffect, useState } from 'react';
function App() {
     const [count, setCount] = useState(1);
     const add = () => {
      setCount((count) => count + 1);
     };
     useEffect(() => {
        add();
     }, [add]); //add函数作为依赖项
return <div className="App">count: {count}</div>;
}
export default App;
上例中,useEffect 会执行 add 函数从而触发组件的重新渲染,函数的重新渲染会重新生成 add 的引用,从而触发 useEffect 的重新执行,然后再执行 add 函数触发组件的重新渲染... ,从而导致无限循环:
为了避免上述的情况,我们给 add 函数套一层 useCallback 避免函数引用的变动,就可以解决无限循环的问题:
import React, { useCallback, useEffect, useState } from 'react';
function App() {
    const [count, setCount] = useState(1); 
    const add = useCallback(() => {   // 用 useCallback 包裹 add ,只会在组件第一次渲染生成函数引用,之后组件重新渲染时,add 会复用第一次生成的引用。
         setCount((count) => count + 1);
     }, []);
   useEffect(() => {
       add();
     }, [add]);  //当第一次add函数发生变化时会执行useEffect内部的add()函数,此时,虽然add函数再次发生了变化,但是函数的引用并没有发生变化,因此不会再次执行useEffect
   return <div className="App">count: {count}</div>;
     }
export default App;
小结:useCallback缓存的是函数的引用,目的是为了减少不必要的重复渲染,但是也不是任何情况下都适用,一般较为昂贵的函数