react hook性能优化:memo,useCallback阻止不必要的重新渲染

在react函数组件中修改状态会触发整个函数组件的重载,重载过程中会导致函数中的方法重载和组件重新渲染,这个过程中有很多重载和重新渲染是不必要的,我们可以使用memo和useCallback方法来阻止不必要的性能消耗。

首先定义三个基础组件,来观察不使用上述方法之前的渲染情况:

image.png

在最外层父组件中声明count状态和更改count的方法setCount,并定义一个将count重置为0的方法传递给Foo组件,当我们触发count更改时整个App函数都会重载,重载过程中会导致reset方法也被重载,App组件当中引入的Foo和Pure组件都会重新渲染。

image.png

如上图所示,每次点击按钮都会触发两个子组件的重新渲染,但是事实上这两个子组件的重新渲染是没有必要的。

memo

memo的作用是在组件重新渲染前确认内部传入的组件是否需要重新渲染。 这里将Pure组件用memo方法进行嵌套。

image.png

然后再次点击按钮更改状态触发App组件的重新渲染

image.png

可以看到这里再次进行点击,重新渲染的子组件就只有Foo了,由于Pure内部没有状态和属性更改,memo会判定该组件无需重新渲染

useCallback

useCallback的作用是缓存一个函数,并传入相关的依赖项,只有在依赖项改变的时候才会重载函数

我们首先给Foo也包裹memo方法

image.png

点击按钮更改状态触发App组件的重新渲染

image.png

发现即使嵌套了memo,Foo组件还是会不断重新渲染,原因是我们从父组件传入的reset在父组件重载的过程中也被重载了,新的reset !== 上次传入的reset,由于属性发生了更改,因此被认为有必要进行重新渲染,这时就应该用useCallback将reset方法进行缓存,阻止这种不必要的重新渲染。

image.png

此时再触发状态更改

image.png

两个组件都只有初始化渲染,不再触发重新渲染了。

附代码:

import React, { memo, useCallback, useState } from "react";

// 最外层父组件
function App() {
  const [count, setCount] = useState(0)

  const reset = useCallback(() => {
    setCount(0)
  }, [])

  return (
    <div className="App">
      <div>{count}</div>
      <button onClick={() => setCount(count + 1)}>add</button>
      <Foo reset={reset} />
      <Pure />
    </div>
  );
}

// 接收函数
const Foo = memo(function Foo(props) {
  
  console.log('Foo render...');
  return (
    <button onClick={props.reset}>
      reset
    </button>
  )
})

// 纯函数组件
const Pure = memo(function Pure() {
  console.log('pureComponent render...');

  return (
    <div>pureComponent</div>
  )
})

export default App;