大家好,我叫小杜杜,随着Hooks的盛行,我们要想在项目中灵活使用,就必须了解其内部原理,并且学会使用方法,今天来详细看看useMemo和useCallback这两个钩子
useMemo
当一个父组件中调用了一个子组件的时候,父组件的 state 发生变化,会导致父组件更新,而子组件虽然没有发生改变,但也会进行更新。
简单的理解下,当一个页面内容非常复杂,模块非常多的时候,函数式组件会从头更新到尾,只要一处改变,所有的模块都会进行刷新,这种情况显然是没有必要的。
我们理想的状态是各个模块只进行自己的更新,不要相互去影响,那么此时用useMemo
是最佳的解决方案。
这里要尤其注意一点,只要父组件的状态更新,无论有没有对自组件进行操作,子组件都会进行更新,useMemo
就是为了防止这点而出现的
在讲 useMemo
之前,我们先说说memo
,memo
的作用是结合了pureComponent纯组件和 componentShouldUpdate功能,会对传入的props进行一次对比,然后根据第二个函数返回值来进一步判断哪些props需要更新。(具体使用会在下文讲到~)
useMemo
与memo
的理念上差不多,都是判断是否满足当前的限定条件来决定是否执行callback
函数,而useMemo
的第二个参数是一个数组,通过这个数组来判定是否更新回掉函数
这种方式可以运用在元素、组件、上下文中,尤其是利用在数组上,先看一个例子:
useMemo(() => (
<div>
{
list.map((item, index) => (
<p key={index}>
{item.name}
</>
)}
}
</div>
),[list])
从上面我们看出 useMemo
只有在list
发生变化的时候才会进行渲染,从而减少了不必要的开销
总结一下useMemo
的好处:
- 可以减少不必要的循环和不必要的渲染
- 可以减少子组件的渲染次数
- 通过特地的依赖进行更新,可以避免很多不必要的开销,但要注意,有时候在配合
useState
拿不到最新的值,这种情况可以考虑使用useRef
解决
useCallback
useCaack
与useMemo
极其类似,可以说是一模一样,唯一不同的是useMemo
返回的是函数运行的结果,而useCallback
返回的是函数
注意:这个函数是父组件传递子组件的一个函数,防止做无关的刷新,其次,这个组件必须配合memo
,否则不但不会提升性能,还有可能降低性能
import React, { useState, useCallback } from 'react';
import { Button } from 'antd-mobile';
const MockMemo: React.FC<any> = () => {
const [count,setCount] = useState(0)
const [show,setShow] = useState(true)
const add = useCallback(()=>{
setCount(count + 1)
},[count])
return (
<div>
<div style={{display: 'flex', justifyContent: 'flex-start'}}>
<TestButton title="普通点击" onClick={() => setCount(count + 1) }/>
<TestButton title="useCallback点击" onClick={add}/>
</div>
<div style={{marginTop: 20}}>count: {count}</div>
<Button onClick={() => {setShow(!show)}}> 切换</Button>
</div>
)
}
const TestButton = React.memo((props:any)=>{
console.log(props.title)
return <Button color='primary' onClick={props.onClick} style={props.title === 'useCallback点击' ? {
marginLeft: 20
} : undefined}>{props.title}</Button>
})
export default MockMemo;
我们可以看到,当点击切换按钮的时候,没有经过 useCallback
封装的函数会再次刷新,而进过过 useCallback
包裹的函数不会被再次刷新
End
最后,一定要有效的利用 useRef
去结合useMemo
、useCallback
做性能优化,写出高质量的组件,一定要多多实现,喜欢的点个👍吧~