zoukankan      html  css  js  c++  java
  • 为什么要在函数组件中使用React.memo?

    初探memo

    首先让我们用一个例子走进React.memo的世界

    呆呆的函数组件 - 没有使用memo

    对于一个函数组件来说,如果没有使用React.memo就好比是一个人没有脑子,就笨笨的呆呆的

    不信我们就来看下面的Demo

    点击访问演示Demo

    GIF打开UC浏览器 查看更多精彩图片

    让我们来分析下上图发生的流程:

    1. 页面第一次加载,渲染App组件和B组件,控制台打印效果如上图

    2. 点击按钮,改变App组件内的值。App组件和B组件全都发生更新那么问题就来了,按正常逻辑来说,应该是这样的流程才对:

    3.页面第一次渲染,App组件和B组件分别更新,并打印App组件内的数据发生变化所以,App组件重新渲染改变的数据和B组件毛关系没有,B组件维持原状,不进行更新渲染but理想异常丰满的,现实十分骨干的。 事实就是不但App组件发生了更新,B组件也跟着进行了更新,这不是我们想要的,因为对于B组件来说:明明老子啥都没干,却还非要我再重新穿一遍衣服?

    无效渲染的原因

    那么造成无效渲染的原因是啥呢?

    其实简单说来是这样的:函数组件本身没有识别prop值的能力,每次父组件更新的时候都相当于是给子组件一个新的prop值。所以就相当于B组件这小子因为没带脑子(React.memo),是个呆呆的二傻子,所以他做为一个普通组件,就没有分别prop的能力,当他看到别人都更新了也就跟着把自己也造了一遍,因此就会造成上面中的问题。

    给憨憨带上脑子 - 使用memo进行包裹

    给函数组件带上脑子 当我们给一个函数组件带上脑子的时候,就想下面这样

    就不会发生上面那种,无脑render组件的情况了

    试着把上面demo中B组件代码里最后一行的注释放开试一下吧

    然后像上面一样再次点击一下按钮,看看控制台的打印结果:

    GIF打开UC浏览器 查看更多精彩图片

    Yep! 只更新了App组件,符合预期!

    那么到底是为什么造成的这种原因呢

    所以到这里还不算完,让我们进一步升温

    激情升温 - 深入探索

    到这里其实我们还是不太清楚memo是怎么做到避免无效更新的,接下来我们就来扒一扒!

    class组件中的性能优化点

    不知道大家有没有发现class组件中也有一个这样作用的东西,叫做PureComponent,它的功能和memo是一毛一样的。

    来回顾一下,我们在class组件中经常用到的写法:

    总的来说其实PureComponnet和memo都是通过对props值的浅比较来决定该组件是否需要更新的。

    如果我们在class组件中,不主动使用PureComponent,也可以手动的去决定该组件是否更新,具体做法:

    在生命周期shouldComponentUpdate,来通过对当前porps以及state值的对比,然后返回一个布尔值(true或者false)来决定该组件是否更新。其实PureComponent组件就是把这对比值的部分功能帮我们完成了,方便我们直接使用,而不用再去手动的去写代码进行类似的优化。

    memo的功能实现

    这里是我的猜想哈,memo的原理和PureComponent应该是一样的,从开发者的角度去想,既然class组件有这样一个优化方法,那既然要推行Hook,函数组件也必定需要一个类似功能的方法去帮助大家减少代码优化的工作量。所以感觉两者在功能的实现上应该大部分都是一致的。 这里也放上一段React中PureComponent进行浅比较的代码,方便大家进一步理解

    这就是react中进行浅层比较的源码,也是PureComponent和memo决定是否更新组件的重要依据。

    memo配合useMemo、useCallback

    一般在项目的优化实践中,memo包裹的函数组件都是要配合useMemo和useCallback来使用的

    对于useMemo和useCallback其实我不准备长篇大幅的讲述了,因为社区已经有很多不错的文章了,大家可以搜来看一下。 我这里只做一个说人话的简单介绍就好了

    useCallback

    返回值是一个函数(memoizedCallback),这个函数就是作为第一个参数传进去的那个。区别就是作为返回值的这个函数是一个memoized的版本,用人话理解就是:保持了函数的引用。不会在组件更新时,去重新声明函数,从而改变在内存中的引用地址。除非是第二个参数数组里的依赖项发生改变,否则这个做为返回值的函数(memoizedCallback)就一直保持原先的状态

    应用场景

    经常使用在父组件A向子组件B传递一个函数作为prop值的时候

    父组件A:

    子组件B:

    useMemo

    其实和useCallback很像,只不过是useMemo返回的是一个值,而不是一个函数useCallback 的第一个参数是函数,这个函数的返回值会作为useMemo的返回值memoizedValue)除非是第二个参数数组里的依赖项发生改变,否则这个做为返回值(memoizedValue)就一直保持原先的值

    useCallback能做的事useMemo都能做,但是还是推荐各司其职

  • 相关阅读:
    JavaScript 19 数组(二)
    JavaScript 19 数组(一)
    JavaScript 18 字符串(三)
    JavaScript 18 字符串(二)
    JavaScript 18 字符串(一)
    History 5 : Silk Roads / Mongols / Ottoman and Mughal Empires
    History : Pictures of History
    001 markdown基本语法
    c#知识结构图
    c#知识结构图
  • 原文地址:https://www.cnblogs.com/plBlog/p/15320659.html
Copyright © 2011-2022 走看看