memo 和 useCallback 搭配使用

memo 和 useCallback 搭配使用

前言,开发时,当父组件重新渲染时,它的子组件也会跟着重新渲染。但是有一种情况,就是我子组件的数据是没有发生改变的,是不需要进行重新渲染。这个时候,就可以采用 memo 和 useCallback 搭配对组件进行一个优化。

01 需求

父组件 App 里面有了 A 组件、B 组件,父组件 App 管理 count 数据,A 组件负责展示 count 数据,B 组件展示按钮,负责 count 相关操作。

image-20220406153329424

如图所示,但是,我只想说当 count 改变时,只更新 A 组件重新渲染。B 组件是没有必要重新渲染的,减少性能开销

02 源码解析

reactHooks 组件对 props 的浅比较是在 memo 里面比较的(类组件是在 shouldComponentUpdate 里面),如果没有 memo,那么你使用 useCallback 就没啥意义,反而浪费性能(因为 useCallback 来包裹函数也是需要开销的)。因为子组件还是会重新渲染。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// App 父组件
import React, { useCallback, useState } from 'react'
import A from './components/A'
import B from './components/B'

function App() {
const [count, setCount] = useState(0)
// 返回是一个 memoized 回调函数, 搭配B组件的 memo 使用
const add = useCallback(() => setCount((c) => c + 1), [])

return (
<div className="App">
<A count={count} />
<B addCount={add} />
</div>
)
}

export default App
1
2
3
4
5
6
7
8
9
10
11
12
// A组件 子组件
import React from 'react'

export default function A({ count = 0 }) {
console.log('A组件')
return (
<div>
<h1>A组件</h1>
<h2>当前计数为:{count}</h2>
</div>
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// B组件 子组件
import React from 'react'

function B({
addCount = () => {}, // 对 props 进行一次浅比较
}) {
console.log('B组件')
return (
<div>
<h1>B组件</h1>
<button onClick={addCount}>+ 1</button>
</div>
)
}
// 注意这边,添加 memo 对B组件进行包裹
// 当传进的 addCount 没有发生改变时,B组件不会进行渲染
export default React.memo(B)

03 效果

没有进行优化,正常经常,A 和 B 组件都会重新渲染

GIF 2022-4-6 15-47-28

使用 memouseCallback 优化过后

GIF 2022-4-6 15-48-19

04 memo 扩展

默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

1


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!