React中的纯组件

React提供了一种基于浅比较模式来确定是否应该重新渲染组件的类React.PureComponent,通常只需要继承React.PureComponent就可以定义一个纯组件。React.PureComponentReact.Component很相似,两者的区别在于React.Component并未实现shouldComponentUpdate(),而React.PureComponent中以浅层对比propstate的方式来实现了该函数。如果赋予React组件相同的propsstaterender()函数会渲染相同的内容,那么在某些情况下使用React.PureComponent可提高性能。

描述

首先我们来回顾下React组件执行重渲染re-render更新的时机,一般当一个组件的props属性或者state状态发生改变的时候,也就是父组件传递进来的props发生变化或者使用this.setState函数时,组件会进行重新渲染re-render。而在接受到新的props或者state到组件更新之间会执行其生命周期中的一个函数shouldComponentUpdate,当该函数返回true时才会进行重渲染,如果返回false则不会进行重渲染,在这里shouldComponentUpdate默认返回true,因此当组件遇到性能瓶颈的时候可以在shouldComponentUpdate中进行逻辑判断,来自定义组件是否需要重渲染。

我们可以稍微查看一下源码的实现,可以看到PureComponent是通过寄生组合继承的方式继承了Componentcommit id 0cf22a5

// master/packages/react/src/ReactBaseClasses.js line 123
// ...
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype; /**
* Convenience component with default shallow equality check for sCU.
*/
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
} const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// Avoid an extra prototype jump for these methods.
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;
// ...

同时在checkShouldComponentUpdate函数中有一段这样的逻辑,在函数名上就能看出是对传入的参数进行了一次浅比较,因此实际上PureReactComponent组件和ReactComponent组件的区别就是React.PureComponent中以浅层对比propstate的方式来实现了shouldComponentUpdate()函数。

// master/packages/react-reconciler/src/ReactFiberClassComponent.new.js line 334
// ...
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
// ...

需要注意的是,React.PureComponent中的shouldComponentUpdate()仅作对象的浅层比较。如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的比对结果。仅在你的propsstate较为简单时才使用React.PureComponent,或者每次更新都使用新的对象,或者在深层数据结构发生变化时调用forceUpdate()来确保组件被正确地更新,你也可以考虑使用immutable对象加速嵌套数据的比较。此外React.PureComponent中的shouldComponentUpdate()将跳过所有子组件树的prop更新,因此需要确保所有子组件也都是纯的组件。

优点

  • shouldComponentUpdate生命周期做了优化会自动shadow diff组件的stateprops,结合immutable数据就可以很好地去做更新判断。
  • 隔离了父组件与子组件的状态变化。

缺点

  • shouldComponentUpdate中的shadow diff同样消耗性能。
  • 需要确保组件渲染仅取决于propsstate

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://zhuanlan.zhihu.com/p/30659051
https://juejin.cn/post/6844903618848669709
https://juejin.cn/post/6844904099679305741
https://segmentfault.com/a/1190000014979065
https://ginnko.github.io/2018/12/17/pure-component/
https://zh-hans.reactjs.org/docs/react-api.html#reactpurecomponent

React中的纯组件的更多相关文章

  1. React 中的 定义组件的 两种方式

    React 中创建 Components 的方式有两种:Function and Class 定义一个组件最简单的方法就是写一个 JavaScript 函数 function Welcome(prop ...

  2. react中使用截图组件Cropper组件

    --最近项目用react,学习react并使用cropper组件裁剪图片. (这里开发组件不够统一有用tsx(TypeScript + xml/html)写的组件,有用jsx(javascript+x ...

  3. React中的通讯组件

    1.父传子:     传递:当子组件在父组件中当做标签使用的时候,给当前子组件绑定一个自定义属性,值为需要传递的数据     接收:在子组件内部通过this.props进行接收 2.子传父     传 ...

  4. React中实现keepalive组件缓存效果

    背景:由于react官方并没有提供缓存组件相关的api(类似vue中的keepalive),在某些场景,会使得页面交互性变的很差,比如在有搜索条件的表格页面,点击某一条数据跳转到详情页面,再返回表格页 ...

  5. React中的固定组件(随遇随记)

    <React.StrictMode></React.StrictMode>对组件中使用严格模式 <React.Fragment></React.Fragmen ...

  6. React中的高阶组件

    高阶组件(HOC, High-Order Component)是React中用于重组组件逻辑的高级技术,是一种编程模式而不是React的api. 直观来讲,高阶组件是以某一组件作为参数返回一个新组件的 ...

  7. 前端笔记之React(二)组件内部State&React实战&表单元素的受控

    一.组件内部的State 1.1 state state叫状态,是每一个类式组件都有的属性,但函数式组件,没有state. state是一个对象,什么值都可以定义. 在任何类式组件的构造函数中,可以用 ...

  8. 初学React:定义一个组件

    接着聊React,今天说说如何创建一个组件类. <!DOCTYPE html> <html lang="en"> <head> <meta ...

  9. 从 Vue 的视角学 React(四)—— 组件传参

    组件化开发的时候,参数传递是非常关键的环节 哪些参数放在组件内部管理,哪些参数由父组件传入,哪些状态需要反馈给父组件,都需要在设计组件的时候想清楚 但实现这些交互的基础,是明白组件之间参数传递的方式, ...

  10. React中的Ajax

    React中的Ajax 组件的数据来源,通常是通过Ajax请求从服务器获取,可以使用componentDidMount方法设置Ajax请求,等到请求成功,再用this.setState方法重新渲染UI ...

随机推荐

  1. 1. 在Windows10上使用dbca配置oracle19.3.0.0时,报错DBT-50000 无法检查可用内存。

    1.如图所示,在安装过程中,我遇到了错误提示,无法检查可用内存,导致安装失败. 在咨询后,认为是内存不足导致的问题,便清理了内存,重新安装.但是依旧出现以上内容,检查自己的内存大小,远远大于其安装所需 ...

  2. 【Linux】字符驱动之sysfs接口实现

    [来源]https://blog.csdn.net/qq_20553613/article/details/104556269

  3. [转帖]Python学习之十七_django的入门

    Python学习之十七_django的入门 前言 Python学习了一周, 慢慢总结摸索. 自己还是有多不会的地方. 感慨这些年浪费的时间. 所有的时间都是选择大于努力. 努力最多感动自己. 生活是需 ...

  4. 【转帖】TCP内核参数

    https://www.cnblogs.com/chia/p/7799231.html tcp_syn_retries :INTEGER默认值是5对于一个新建连接,内核要发送多少个 SYN 连接请求才 ...

  5. TypeScript中泛型<T>详细讲解

    1.泛型 在定义函数或者接口或者类的时候 不能预先确定要使用的数据类型 而是在使用函数.接口.或者类的时候才能够确定数据类型 这个时候我们就需要使用的是泛型 2.功能描述 我们需要实现一个方法,方法中 ...

  6. mysql系列基础篇01---通用的语法及分类

    通用语法及分类 DDL: 数据定义语言,用来定义数据库对象(数据库.表.字段) DML: 数据操作语言,用来对数据库表中的数据进行增删改 DQL: 数据查询语言,用来查询数据库中表的记录 DCL: 数 ...

  7. Linux命令-tail命令

    Linux命令-tail 命令分析 命令格式 参数 例子 Linux命令-tail 命令分析 tail命令可用于查看文件的内容,通常用来查看日志,加上-f参数就可以查看最新的日志并且不断刷新. 命令格 ...

  8. 什么是 Java 字节码?采用字节码的好处是什么?

    在 Java 中,JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机.Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效 ...

  9. 【二】分布式训练---参数服务器训练(飞桨paddle1.8)

    1.参数服务器训练简介 参数服务器训练是分布式训练领域普遍采用的编程架构,主要解决以下两类问题: 模型参数过大:单机内存空间不足,需要采用分布式存储. 训练数据过多:单机训练太慢,需要加大训练节点,来 ...

  10. 关闭表单验证/关闭控制台async-validator警告

    找到util.js node_modules -> async-validator -> es -> util.js 将console.warn(type, errors)注释 如果 ...