callback 相信大家都不陌生——回调函数 ,但是 callback hooks 的作用是啥呢?用于得到一个固定引用值的函数,通常用它进行性能优化
语法
const func = useCallback(fn, deps)
- 参数 fn: 一个函数,需要保存的函数引用
- 参数 deps: 一个数组,保存函数里面的依赖,如果依赖变化,那么函数的引用地址就会发生变化,否则不执行,这个的用法有点和 effect hooks 类似
案例
有这么一个场景,我们在一个函数组件中,引用了一个类组件(纯组件,数据发生变化才会执行rendrer,),然后在函数组件中做以下事情
。类组件传递数据不改变
。函数组件数据可以自己改变
代码如下:
import React, { PureComponent, useState } from 'react' interface ITestClassCompP { // 数字 count: number, // 点击更改数据 onClick: () => void } // 这是一个存组件,只有props 或者state 变化的时候才会render class TestClassComp extends PureComponent<ITestClassCompP> { render() { console.log('TestClassComp 组件渲染了'); return ( <div> <h1>我是类组件,数据从函数组件穿过来,值是 {this.props.count}</h1> <button onClick={this.props.onClick}> + 1 </button> </div> ) } } // 测试组件 export function TestCallbackHook() { // 状态值 const [count, setCount] = useState(0) console.log('TestCallbackHook 组件渲染了'); // 输入框的值 const [inputVal, setInputVal] = useState(0) return ( <> <TestClassComp count={count} onClick={() => { setCount(count + 1) }} /> <input value={inputVal} type="number" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { setInputVal(parseInt(e.target.value)) }} /> </> ) }
效果
从代码中,我们可以知道,我们点击+ 1 按钮的时候,两个组件需要渲染,但是输入框的数据改变是不应该渲染子组件的,因为我们的count 数据是没有变化的,这是为啥呢?
原因就是在于那个回调函数,还记得属性传入一个函数,如果是直接在事件后面绑定那么每一次render的时候就会重新生成一个函数。并且每一次的函数的地址都不一样,所以这就是为啥 父组件渲染,子组件也会跟着渲染的根本原因。
如何解决
还记得类组件是如何解决这个问题么? 在类组件中,我们的事件绑定函数定义是直接使用 esnext 的语法,定义出来,这样就不会导致每一次的函数引用地址不变了,那么在函数组件可以使用么?
答案是: 不行,有兴趣的自己去尝试
使用 callback hooks 来保存引用
改造函数,如下
最终效果
这个效果才是我们想要的!