重学React:Hooks之useCallback、useMomo

您好,我是沧沧凉凉,是一名前端开发者,目前在掘金知乎以及个人博客上同步发表一些学习前端时遇到的趣事和知识,欢迎关注。


useMomo、useCallback通常都是用来做性能优化,可能你用过某些React组件,但是你没有注意过当某些state状态改变时,组件只有核心的很小的一部分进行了更新,当然,性能优化不一定是正向的,如果你错误的使用useMomo、useCallback,可能使得你的项目性能变得更加的糟糕。

React中是有庞大的学问的,但从本篇文章的标题来看,性能优化相关的话题并不在本篇文章的讨论范围,本篇文章主要还是讲解这些玩意在哪些情况下能够用得到。

React.memo

React中父组件的状态发生了改变,连带的子组件也会重新渲染,这是什么意思?我们可以看一下下面的代码:

noMemo

从控制台我们可以看出,父组件的状态改变时,子组件也会进行重新渲染,如果要解决这个问题,我们就可以使用React.memo,使用了React.memo后如下图所示。

memo

可以发现,使用memo将AppOther组件进行包裹后,返回的是一个拥有缓存的组件,将返回的组件当作子组件时,即使父组件的状态发生了改变,子组件也不会重新进行渲染。

useCallback

接着上面的例子讲,虽然父组件状态改变时子组件不会刷新,但是我们要是让子组件进行改变父组件的状态,那会是怎么个情况呢?

useMomo

比起useCallback我更常用useMomo,因为useMomo返回一个缓存(memoized)值,和useCallback一样,它也同样存在一个依赖项,只有当依赖项发生改变时才会重新计算memoized值。

在js中,其实创建引用类型(数组、对象等等)的数据是非常吃性能的,而从上文中可以看出,React的组件如果没有进行优化,那么每次状态改变都会重新创建,比如下面的代码:

notUseuseMemo

可以看到,每次状态发生了改变都打印了”组件刷新了”这几个字,那如果是下面的情况呢?

createArr

可以发现,每次状态改变,那么函数arr都会执行一次,当然由于这个arr中没有进行任何处理,但是如果是创建长度为1万的数组呢,如果方法中有大量的计算,每次状态改变时就会造成极大的性能开销。同时复杂的页面往往不仅有一个状态,如果每个状态更新都刷新一次组件,那么性能上会是极大的浪费。

如果要解决这个问题,我们直接使用useMemo进行创建一个具有缓存的数组。

useMemo

使用了useMemo后,变量arr的值即为useMemo中回调函数的返回值,值得注意的是,useMemo必须拥有返回值,后面括号中是它的依赖项,如果为空,则useMemo的回调函数仅在组件创建时进行执行,如果有依赖项,则在依赖项改变时会重新执行,如果仅有回调函数,即下面的代码:

const arr = useMemo(() => {
    console.log("创建一个数组");
    return ["123"];
});

那么useMemo就没有必要存在,因为页面上的所有状态改变时,回调函数都会执行。

最后

就我个人来讲useMemo会经常用到,useCallback和React.momo不常使用到,因为我目前做的项目为外包项目,所以往往工期很短,根本没有太多的时间让你进行优化项目,而且项目的优化必须慎重,useCallback和React.momo的使用是有成本的,相当于额外在之前的函数或者组件的基础上包裹了一层新的组件,同时也具有缓存的效果,所以在平时写项目的过程中,如果不是一个非常庞大的业务组件,已经影响到用户体验的情况下,不要轻易做性能优化。

当然,如果你是要封装一些通用的组件,那你可能应该好好研究一下性能优化。