这里提一下,如果大家看到这个标题有所疑惑的话,可以花点时间看一下本篇文章。反之呢如果是看到标题第一时间就反映出结论的话,就可以去get其他文章的知识点了

那么接下来就不废话了,直接长刀直入,进入正题!

初探memo

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

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

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

不信我们就来看下面的Demo

点击访问演示Demo

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

  1. 页面第一次加载,渲染App组件和B组件,控制台打印效果如上图
  2. 点击按钮,改变App组件内的值。App组件和B组件全都发生更新

那么问题就来了,按正常逻辑来说,应该是这样的流程才对:

  1. 页面第一次渲染,App组件和B组件分别更新,并打印
  2. App组件内的数据发生变化所以,App组件重新渲染
  3. 改变的数据和B组件毛关系没有,B组件维持原状,不进行更新渲染

but理想异常丰满的,现实十分骨干的。 事实就是不但App组件发生了更新,B组件也跟着进行了更新,这不是我们想要的,因为对于B组件来说:明明老子啥都没干,却还非要我再重新穿一遍衣服?

无效渲染的原因

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

其实简单说来是这样的:

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

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

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

import React form 'react';const FuncComponent = ()=>{return 

火热很火辣

}export default React.memo(FunComponent);

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

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

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

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

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

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

激情升温 - 深入探索

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

class组件中的性能优化点

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

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

import React, {PureComponent} from 'react';class Demo extends PureComponent {// 性能优化点shouldComponentUpdate(nextProps, nextState){// 默认始终返回truereturn true;  }render() {return 

听懂掌声

}}

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

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

在生命周期shouldComponentUpdate,来通过对当前porps以及state值的对比,然后返回一个布尔值(true或者false)来决定该组件是否更新。

其实PureComponent组件就是把这对比值的部分功能帮我们完成了,方便我们直接使用,而不用再去手动的去写代码进行类似的优化。

memo的功能实现

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

function shallowEqual (objA: mixed, objB: mixed): boolean {  //  这里的is是判断两个值是否相等,只不过是对 + 0 和 - 0,以及 NaN 和 NaN 的情况进行了特殊的处理封装,目前react源码中好像有一套新的is判断  if (is (objA, objB)) {    return true;  }  // 判断是否为对象类型  if (    typeof objA !== 'object' ||    objA === null ||    typeof objB !== 'object' ||    objB === null  ) {    return false;  }  // 比较两个对象的,属性数量是否相等  const keysA = Object.keys (objA);  const keysB = Object.keys (objB);  if (keysA.length !== keysB.length) {    return false;  }  // 比较两个对象的的属性是否相等,值是否相等  for (let i = 0; i < keysA.length; i++) {    if (      !hasOwnProperty.call (objB, keysA [i]) ||      !is (objA [keysA [i]], objB [keysA [i]])    ) {      return false;    }  }  return true;}

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

memo配合useMemo、useCallback

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

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

useCallback

  const memoizedCallback = useCallback(    () => {      doSomething(a, b);    },    [a, b],  );

返回值是一个函数(memoizedCallback),这个函数就是作为第一个参数传进去的那个。区别就是作为返回值的这个函数是一个memoized的版本,用人话理解就是:保持了函数的引用。不会在组件更新时,去重新声明函数,从而改变在内存中的引用地址。

除非是第二个参数数组里的依赖项发生改变,否则这个做为返回值的函数(memoizedCallback)就一直保持原先的状态

应用场景

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

父组件A:

import React,{ useCallback } form 'react';const A = () => {return (    // 如果不使用useCallback包裹的话,每次A的更新,都会重新声明这个handleClick的这个函数,导致B组件无效的更新      //doSomething,[x,xx]) };    );}export default A;

子组件B:

import React,{ memo } form 'react';const B = (props) => {const { handleClick } = props;return 
卑微小B在线被Diss

;}// 这里需要注意,要配合memo使用,否则的话不带脑子的B组件会始终认为传递过来的prop值都是一个全新的export default memo(B);

useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

其实和useCallback很像,只不过是useMemo返回的是一个,而不是一个函数

useCallback 的第一个参数是函数,这个函数的返回值会作为useMemo的返回值memoizedValue)

除非是第二个参数数组里的依赖项发生改变,否则这个做为返回值(memoizedValue)就一直保持原先的值

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

const fn = useCallback( () => //doSomething , [x,xx])// 相当于const fn = useMemo( ()=> () => //doSomething , [x,xx])// 因为useMemo的返回值是第一个函数的返回值,所以只要让第一个参数的函数返回一个函数就可以达到useCallback的效果

结尾 需要这些资料,可以私信 666 领取

react组件放在数组中_为什么要在函数组件中使用React.memo?相关推荐

  1. asp.net怎么实现按条件查询_用这个提取函数王中王,制作数据查询表

    当Excel表的数据太多时,需要进行数据的查询与提取,往往要使用查找与引用函数.提取条件简单还好说,一复杂起来,就要使用又长又头疼的嵌套函数,不要说用了,光看懂函数都要死一片脑细胞. 别伤脑筋了,为什 ...

  2. Linux中main和初启函数,main 中的 argv和argc 到底是个啥意思?

    原标题:main 中的 argv和argc 到底是个啥意思? 前言 一般我们平时写main函数的话,一般都是写不带参数的比较多,而且也习惯了这样写:其实标准的形式写法,main函数是带两个参数的,这两 ...

  3. python 结构体数组 定义_一篇文章弄懂Python中所有数组数据类型

    前言 数组类型是各种编程语言中基本的数组结构了,本文来盘点下Python中各种"数组"类型的实现. list tuple array.array str bytes bytearr ...

  4. python数组类型_一文搞懂Python中的所有数组数据类型

    关于我 编程界的一名小小程序猿,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. 联系:hylinux1024@gmail ...

  5. c++ 数组截取_【学习教程】JavaScript中原生Array数组方法详解

    来源 | http://www.fly63.com/article/detial/9692 JS中,数组可以通过阵列构造函数或[]字面量的方式创建.数组是一个特殊的对象,继承自对象原型,但用typeo ...

  6. c++中函数放在等号右边_如何从C或C++中的函数返回多个值?

    新程序员通常在寻找从函数返回多个值的方法.不幸的是,C和C++不允许直接这样做.但是幸运的是,通过一些巧妙的编程,我们可以轻松实现这一目标. 下面是从C函数中返回多个值的方法: 通过使用指针. 通过使 ...

  7. store 存取数据数组对象_如何从Firestore文档中获取对象数组

    我在Firestore中有一个如下所示的数据结构: 父POJO是:public class Restaurant { private Double distance; private GeoPoint ...

  8. wepy组件子父传值_微信小程序wepy框架中父组件与子组件通信和交互

    官网上描述: $broadcast$broadcast事件是由父组件发起,所有子组件都会收到此广播事件,除非事件被手动取消.事件广播的顺序为广度优先搜索顺序.$emit$emit与$broadcast ...

  9. su组件在什么窗口_如何在草图大师SketchUp中创建窗口组件?

    草图大师创建窗口组件技巧教程: 1.使用矩形工具并创建一个窗口大小的矩形. 2.删除矩形的内部. 3.选择要删除的窗口左侧的四个边缘. 4.选择四个边缘后,右键单击其中之一,然后单击"制作组 ...

最新文章

  1. poj 2392 Space Elevator
  2. android pcm频谱_Android音频可视化
  3. 50个运维必会的常识和操作
  4. Underscore.js 初探
  5. jq点击按钮获取php的值删除,通过jquery怎么移除点击事件
  6. spring5新特性
  7. C语言变长数组data[0]【总结】
  8. 电脑音频服务未运行怎么解决_电脑提示音频服务未运行怎么办,快来看看吧,图片描述(最多50字)...
  9. 滴滴滴,测试工程师简历模板分享一波
  10. ViewPager里面ImageView图片切换出现bug
  11. wos 文献被引_全世界最权威的文献检索工具,这6个检索技巧必须要掌握!
  12. linux 系统运维小工具
  13. 微信小程序布局 底部位置固定例子
  14. 美国TJX公司 - MBA智库百科
  15. “立字据,你们这群混蛋!”
  16. mysql not null 语法_[MySQL]--MySQL表中某个列插入数据总被截断,报编码方式的语法错误,实际是column的not null属性和更改编码语法导致的冲突。...
  17. 用python把图片换成蓝底_Python给照片换底色(蓝底换红底)
  18. java的逻辑常量_在Java语言中,逻辑常量只有true和(__)两个值;
  19. 工厂生产线设备数据采集方法
  20. 短线绝招--潜龙出海

热门文章

  1. python 利用matplotlib中imshow()函数绘图
  2. 使用 Python 在 Linux 上实现一键回归测试
  3. python中json.dump() 和 json.dumps() 有那些区别?
  4. php 时钟函数,使用PHP的日期与时间函数技巧
  5. ubuntu虚拟机apt报错:No module named ‘uaclient‘(替换所有的python3为/usr/bin/python3)xftp、xshell不能连接
  6. C语言sprintf函数(发送格式化输出到 str 所指向的字符串)(format 标签属性)(字符串拼接)(数字转字符串、浮点数转字符串)
  7. LabelImg 批量生成标注图片文件夹序号(起始值+终值)
  8. 目标、物体识别(检测)object detection 中的 bounding boxes 是什么? 边界区域、边界框、边界盒
  9. python 如何生成特定间隔数列?range()、numpy.arange()
  10. 洛谷【算法1-4】递推与递归