介绍

useMemouseCallback是React中优化是常用的两个Hooks。它们有一些共同点,比如都需要传递一个依赖数组,只有当依赖项发生改变时才会更新数据。但是它们的使用场景一般不同,下面将具体分析两个Hooks的异同。

useMemo

useMemo的定义如下:

useMemo(factory, Dependencies)

其中factory是工厂函数, Dependencies是其所有依赖值的数组。

在组件初始化的时候会调用factory函数,并将返回值存储起来。当组件需要重新渲染时,react会首先依次判断每个依赖项的值是否发生了变化。如果没有变化,则直接使用之前的存储的返回值,而不会再次调用factory,如果依赖项发生变化,则会使用更新后的依赖项调用factory函数,返回最新的值。

这个Hooks的作用是能够避免一些消耗资源的运算,从而提高性能。下面是一个例子:

 1import React from 'react'
 2funtion MyComponent({n}) {
 3  // 返回斐波那契数列的第n项     
 4  function Fibonaccin){
 5    // ...     
 6  }     
 7  return    
 8  <div>    
 9    斐波那契数列的第{n}项是:{Fibonacci(n)}   
10  </div> 
11}

在上面这个组件中,每次组件重新渲染都会重新调用Fibonacci函数,即使n的值没有发生变化。这样如果n的值比较大的时候就会非常耗费性能,可以改为下面的写法。

 1import React, { useMemo } from 'react' 
 2funtion MyComponent({n}) {   
 3  // 返回斐波那契数列的第n项   
 4  function Fibonaccin){   
 5    // ...    
 6  }    
 7  const fibo = useMemo(() => Fibonacci(n), [n])  
 8  return      
 9  <div>       
10    斐波那契数列的第{n}项是:{fibo}     
11  </div> 
12}

使用useMemo包裹后如果n的值没有发生变化,就不会重新调用Fibonacci函数,节约了性能。如果n的值足够大,节约的性能是非常可观的。

useCallback

useCallback的定义与useMemo类似:

useCallback(callback, Dependencies)

callback是一个函数对象,Dependencies是依赖项数组。

如果依赖项数组中的数据没有发生变化,则会返回上一次的callback函数。

默认情况下,每当一个组件中重新渲染,其中的函数都会重新声明。这样就会导致一个问题:如果该组件将这个函数传递给子组件,那么子组件也会重新渲染,但有时这样的渲染是不必要的。比如下面的例子:

 1import React from 'react'
 2funtion Parent(num) {    
 3  funtion handleClick(  ){   
 4    // 处理点击事件      
 5    console.log(num)    
 6  }  
 7
 8  return     
 9  <div>                
10    <Child onClick={()=>handleClick()} />   
11  </div> 
12}
13
14

每次父组件更新时,子组件也会重新渲染,无论子组件的内容是否发生了变化。如果需要优化可以改为下面的写法:

 1import React, { useCallback } from 'react' 
 2funtion Parent(num) {   
 3  const handleClick = useCallback(() => {     
 4    // 处理点击事件       
 5    console.log(num)   
 6  }, [num])
 7  // 只有当num发生改变时子组件接收到的回调函数才会发生变化 
 8  return        
 9  <div>          
10    <Child onClick={()=>handleClick()}  />    
11  </div> 
12}

这样如果num的值没有发生变化,子组件接收到的回调函数就不会改变,也就不会因此触发渲染。

其他

其实useCallback就是useMemo的第一个参数的返回值是函数时的特殊情况,官方文档中也说明了使用useMemo来缓存一个函数与直接使用useCallback的效果是完全相同的,只是写法上会比较复杂,比如我们可以利用useMemo实现一个我们自己的useMyCallback:

 1fuction useMyCallback(callback, deps){  
 2  useMemo(() => () => callback, deps)
 3}

这样的效果和useCallback是完全相同的。

总结

useMemouseCallback都是用来优化性能的Hooks。本质上useCallback是对useMemo做了一层包装,作用都是通过判断依赖项是否改变来决定是否更新值,只不过useCallback的值是一个函数对象。

useMemo一般通过减少不必要的复杂计算来优化性能,useCallback一般用于给子组件传递回调函数时,减少子组件的渲染次数,从而优化性能。

个人笔记记录 2021 ~ 2025