useCallback 概述
1、useCallback
是在React 中多次渲染缓存函数的 Hook,返回一个函数的 memoized
的值;
2、如果多次传入的依赖项不变,那么多次定义的时候,返回的值是相同的,防止频繁触发更新;
3、多应用在 父组件为函数式组件,子组件也为函数式组件,并且子组件被 React.memo()
包裹着;
4、主要用于性能优化,即使不适用useCallback,代码也要能正常运行;
useCallback 基本用法
写法
let memoizedCallback = useCallback(fn, dependencies)
第一个参数:fn 是想要缓存的函数,可以接收任何参数并返回任何值;React 中会在初始化时候调用,而不是渲染时候调用;
当执行下一次渲染时候,如何出入的依赖值 dependencies
相同,则会返回相同的函数 memoizedCallback
;
相反 若依赖值 dependencies 不同
,则会返回新的函数 memoizedCallback,但是 React 不会主动去调用 memoizedCallback函数,需要开发者自己决定什么时候
执行调用函数;
第二个参数:
dependencies
:是否要更新 fn 的所有响应式值的一个列表,可以传入空数组:[]
;
响应式值包括 props、state
,和所有在你组件内部直接声明的变量和函数。
useCallback 示例
1、为什么要使用 useCallback
当我们传入相同值的时候,不管是对象类型,还是基本类型,都不希望子组件进行更新渲染;
在不需要大量渲染的时候,性能还可以,但是当数据量大的时候,若相同的数据也触发子组件渲染,则会出现性能问题;
2、在不使用 useCallback()
的时候
每次触发 handleAdd
事件时候,都会渲染子组件 ChildA
// 父组件
import { useCallback, useState} from 'react'
import ChildA from './childA'
export default function MyCallBack() {
const [useInfo, setUseInfo] = useState({
name: 'Andy',
age: 18
})
const myCallback = () => {
console.log('==useCallback==')
return useInfo.name
}
const handleAdd = () => {
setUseInfo({
name: 'Andy',
age: 18
})
}
return (
<div>
<h3>This is a MyCallBack demo .---{count}</h3>
<button onClick={handleAdd}>add</button>
<hr />
<ChildA onAddCount={myCallback} ></ChildA>
</div>
)
}
// 子组件
import React, { memo } from 'react'
const ChildA = memo(({onAddCount}) => {
console.log('==ChildA 组件更新了=', count)
return (
<div>
<h3>This is a ChildA demo .</h3>
<button onClick={onAddCount}>子组件</button>
<hr />
</div>
)
})
当我们点击 add
按钮时候,发现页面打印 “==ChildA 组件更新了=
”,说明传入相同的数据时候,会触发子组件渲染;如图所示
3、使用 useCallback 时候
import { useCallback,useState} from 'react'
import ChildA from './childA'
export default function MyCallBack() {
console.log('===父组件callback==')
const [count, setCount] = useState(0)
const [useInfo, setUseInfo] = useState({
name: 'Andy',
age: 18
})
const myCallback = useCallback(() => {
console.log('==useCallback==')
return useInfo.name
}, [useInfo.name])
const handleAdd = () => {
setUseInfo({
name: 'Andy',
age: 18
})
}
return (
<div>
<h3>This is a MyCallBack demo .---{count}</h3>
<button onClick={handleAdd}>add</button>
<hr />
<ChildA onAddCount={myCallback} ></ChildA>
</div>
)
}
// 子组件
import { memo } from 'react'
// eslint-disable-next-line react/display-name
const ChildA = memo(({useInfo, count, onAddCount}) => {
console.log('==ChildA 组件更新了=', count)
const handleChangeName = () =>{
setName('Tom')
}
return (
<div>
<h3>This is a ChildA demo .</h3>
<h4>{count}</h4>
<h4>姓名:{useInfo?.name || '--'}</h4>
<h4>年龄:{useInfo?.age || '--'}</h4>
<button onClick={onAddCount}>子组件</button>
<hr />
</div>
)
})
export default ChildA
在点击 add
按钮 更新相同数据时候,只有父组件渲染,子组件不会再渲染
;如图:
总结
若要实现 传入相同数据时候,只更新当前组件,而子组件不进行渲染,需使用 useCallback() 和 memo 来处理;