memo hooks 这个钩子也是用来做优化性能操作的,大家一定还记得 React.memo() 这个是啥呢,是要给高阶组件,用来给函数组件做性能优化的,作用类似 类组件 的 pureComponent,那么 memo hooks 和 React.memo() 有没有联系呢? 没有,虽然都是为函数组件做性能优化的,但是优化的方向是不一样的(纯组件优化方向详情)。
语法
const list = useMemo(() => fn(a, b), [a, b])
- 参数一fn: 任何稳定的复杂数据,这里指的稳定的是指,数据计算量大的,并且不会实时变化,但是在组件中渲染会被重复渲染的数据。
- 参数二 deps: 依赖的数据,数据变化后,立即执行函数
- 返回值: 由里面的函数执行结果的返回值决定
看到这个hooks 是不是感觉和一个 hooks 好像, callback hooks(详情),其实 callback hooks就是 momo hooks 里面的一部分,用来固定函数的引用地址不变的,但是 momo hooks 可以实现callback 的功能,还可以固定其他类型的数据
案例
改造callback hooks 案例
效果可以实现一样的,原来还是一样的,memo hooks 固定了函数的引用地址,useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
memo hooks 固定其他数据类型的案例
假如我们需要实现一个这样的业务场景,在一个函数组件中,有一个特别大数据的列表,并且当前组件中其他组件可以改变状态值。那么我们可以推断一下预期结果,数据渲染只有在初始化的时候渲染,只要我本身组件数据没有改变,那列表就不应该渲染。
扯远了,回到我们的案例代码如下:
import React, { useCallback, useState } from 'react' interface IListTempCompP { // 值 value: string, } function ListTempComp(prop: IListTempCompP) { console.log('ListTempComp 组件渲染了'); return ( <> <li>列表值:{prop.value}</li> </> ) } export default function TestMemoHook() { // 手动来创建一个大数据 const [range, setRange] = useState({ min: 0, max: 10000 }); const lis = []; // 把数据放入数据 for (let index = range.min; index < range.max; index++) { lis.push( <ListTempComp key={index} value={index.toString()} /> ) } // 其他数据 const [inputVal, setInputVal] = useState(0) // 定义change事件,养成习惯,防止其他的组件调用当前组件,导致重复渲染 const inputHandle = useCallback( () => { setInputVal(inputVal + 1) }, [inputVal], ) return ( <div> <input type="number" value={inputVal} onChange={ inputHandle } /> <ul> {lis} </ul> </div> ) }
效果
这里的效果大家应该猜到了,就是每一次input 的值发生变化,就会输出 10000 次 ListTempComp 组件渲染了
从我这里打印的结果来看,每一次都会render是不对的,那么我们就要去优化他
优化方法
结论
这样就不会每一次点击的时候,在去渲染子组件了,从这么hooks 来看,我们知道 callbackHook, memoHook, 都哪来给函数组件做数据稳定的,顺便提一下,为啥函数组件只要内部的任何state 状态变化就会导致整个组件重新渲染?而类组件不会呢?
- 函数组件我们知道state hook 中只要调用 setData 并且数据变化就会重新渲染该组件,
- 类组件(纯组件)执行 this.setState({}) 不会导致整个组件销毁到重新生成,是因为类组件中有生命周期,只要没有让组件销毁,那么 this.setState({}) 只会重新执行render 函数,其他的数据都是独立的,而render 函数只是类实例中的一个属性。