React的Component,PureComponent源码解析(二)
1.什么是Component,PureComponent?
都是class方式定义的基类,两者没有什么大的区别,只是PureComponent内部使用shouldComponentUpdate(nextProps,nextState)方法,通过浅比较(比较一层),来判断是否需要重新render()函数,如果外面传入的props或者是state没有变化,则不会重新渲染,省去虚拟dom的生成和对比过程,从而提高性能。
2.PureComponent应用
一般用于纯函数
3.Component源码分析
/*
Component 基类
1.设置react的props,content,refs,updater等属性
2.要知道class继承是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this
class A extends React.Component{construcroe(){props){super(props)}}
*/
function Component(props, context, updater) {
this.props = props;//父子传递数据
this.context = context;//爷孙传递数据
this.refs = emptyObject; //子到父传递数据
this.updater = updater || ReactNoopUpdateQueue; //更新数据
}
Component.prototype.isReactComponent = {};//给Component原型上添加属性
/*
使用setState来改变Component类内部的变量 enqueueSetState调用这个方法实现更新机制
partialState:要更新的state,可以是object/function
*/
Component.prototype.setState = function (partialState, callback) {//给Component原型上添加方法
//判断setState中的partialState是否符合条件 如果不符合 则抛出错误
if (!(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null)) {
{
throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");
}
}
//state的更新机制 在react-dom中实现 不同平台更新内容可能不同
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
//在Component的深层次改变但是没有调用setState时 调用此方法 强制更新一次
Component.prototype.forceUpdate = function (callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
4.PureComponent源码解析
function ComponentDummy() { }
// ComponentDummy的原型继承Component的原型
ComponentDummy.prototype = Component.prototype;
function PureComponent(props, context, updater) {//构造函数属性(实例属性),会被实例共享,但不会被修改
this.props = props;
this.context = context;
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
//不能直接继承Component 因为如果是直接继承Component 还会继承它的Constructor方法 目的:减少一些内存使用
var pureComponentPrototype = PureComponent.prototype = new ComponentDummy();
//实例沿着原型链向上查询,只要是自己继承的,都被认作自己的构造函数
pureComponentPrototype.constructor = PureComponent;
//这里做了优化 把 Component.prototype属性浅拷贝到pureComponentPrototype上 防止原型连拉长 导致方法的多层寻找 减少查询次数
_assign(pureComponentPrototype, Component.prototype);
//添加了这个isPureReactComponen参数 来判断是Component还是PureComponent组件
pureComponentPrototype.isPureReactComponent = true;
5.PureComponent如何实现是否需要更新,来提高性能?
//这个变量用来控制组件是否需要更新 默认为true进行更新操作
var shouldUpdate = true;
// inst是组件实例 如果PureComponent定义有shouldComponentUpdate方法 则和Component基类一样
if (inst.shouldComponentUpdate) {
shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
} else {
if (this._compositeType === CompositeType.PureClass) {
// 用shallowEqual函数对比 props 和 state 的改动
// 如果都没改变就不用更新
shouldUpdate =
!shallowEqual(prevProps, nextProps) ||
!shallowEqual(inst.state, nextState);
}
}
1.shallowEqual函数解析
目的:比较值相等,或者对象含有相同的属性、且属性值是否相等
function is(x, y) { //处理了基本类型的比较
//1,针对+0===-0的情况
//2. 针对NaN!==NanN的情况
return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y
;
}
var is$1 = typeof Object.is === 'function' ? Object.is : is;
var hasOwnProperty$2 = Object.prototype.hasOwnProperty;
//返回值:false更新 true不更新
function shallowEqual(objA, objB) {
if (is$1(objA, objB)) {//基本数据类型 不更新
return true;
}
//由于Object.is 可以对基本数据类型做一个精确的比较 如果不等只有一种情况 那就是object, objA/objB中,只要有一个不是object或为null则返回false
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
return false;
}
//过滤掉基本数据类型 就是对象比较 首先比较长度 优化性能
//比较oldProps和新的Props以及oldState和newState长度是否相同 如果长度不同则重新更新渲染 如果长度相同则不用重新渲染 如果不相等 不会往下执行 优化性能
var keysA = Object.keys(objA);
var keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
//如果key相等
//如果objA的属性不在objB里,或者是objA的属性值和objB的属性值不等 则重新渲染 不考虑当keysA[i]为对象的多层问题 浅显比较 提高性能
for (var i = 0; i < keysA.length; i++) {
if (!hasOwnProperty$2.call(objB, keysA[i]) || !is$1(objA[keysA[i]], objB[keysA[i]])) {
return false;
}
return true;
}
}
1.理解:is()函数 x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y 解决了NaN不等于NaN的情况和-0===+0的情, 实现了Object.is
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
2.Object.prototype.hasOwnProperty 用来判断某个属性是否是对象自身的属性
3.浅比较的使用
对象的value是简单数据类型
const a={c:1,d:2}
const b={c:1,d:2}
Object.is(a,b) //false
hasOwnProperty.call(b, 'c') //true
Object.is(a['c'], b['c']) //true
对象的value有复杂数据类型
const a={c:{e:3},d:2}
const b={c:{e:3},d:2}
hasOwnProperty.call(b, 'c') //true
//可以看到,只能用于浅比较 这里会出现错误判定 从而重新更新render
Object.is(a['c'], b['c']) //false
注意点:shouldComponentUpdate(nextProps,nextState) 返回false阻止更新 挂载阶段是不起作用的 更新阶段起作用 图如下

React的Component,PureComponent源码解析(二)的更多相关文章
- Component、PureComponent源码解析
1.什么是Component,PureComponent? 都是class方式定义的基类,两者没有什么大的区别,只是PureComponent内部使用shouldComponentUpdate(nex ...
- Mybatis源码解析(二) —— 加载 Configuration
Mybatis源码解析(二) -- 加载 Configuration 正如上文所看到的 Configuration 对象保存了所有Mybatis的配置信息,也就是说mybatis-config. ...
- RxJava2源码解析(二)
title: RxJava2源码解析(二) categories: 源码解析 tags: 源码解析 rxJava2 前言 本篇主要解析RxJava的线程切换的原理实现 subscribeOn 首先, ...
- Sentinel源码解析二(Slot总览)
写在前面 本文继续来分析Sentinel的源码,上篇文章对Sentinel的调用过程做了深入分析,主要涉及到了两个概念:插槽链和Node节点.那么接下来我们就根据插槽链的调用关系来依次分析每个插槽(s ...
- iOS即时通讯之CocoaAsyncSocket源码解析二
原文 前言 本文承接上文:iOS即时通讯之CocoaAsyncSocket源码解析一 上文我们提到了GCDAsyncSocket的初始化,以及最终connect之前的准备工作,包括一些错误检查:本机地 ...
- jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究
终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...
- Common.Logging源码解析二
Common.Logging源码解析一分析了LogManager主入口的整个逻辑,其中第二步生成日志实例工厂类接口分析的很模糊,本随笔将会详细讲解整个日志实例工厂类接口的生成过程! (1).关于如何生 ...
- erlang下lists模块sort(排序)方法源码解析(二)
上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...
- element-ui 源码解析 二
Carousel 走马灯源码解析 1. 基本原理:页面切换 页面切换使用的是 transform 2D 转换和 transition 过渡 可以看出是采用内联样式来实现的 举个栗子 <div : ...
随机推荐
- 小sun的假期【牛客】
链接:https://ac.nowcoder.com/acm/contest/1085/A来源:牛客网 应肖老师要求前来更新水一水 题目描述 小 sun 非常喜欢放假,尤其是那种连在一起的长假,在放假 ...
- 《深入理解java虚拟机》读书笔记六——第七章
第七章 虚拟机类加载机制 1.类加载的时机 虚拟机的类加载机制: 虚拟机把描述类的数据从class文件中加载到内存,并对数据进行校验.转换解析和初始化,最终形成了可以被虚拟机直接使用的Java类型,这 ...
- Selenium3+python自动化012-测试用例模块化
测试用例模块化特点:为po模型做准备. 1.提取公共方法. 2.提取数据. 3.提取逻辑. # @Author:lsj # @version V1.0 # -*- coding:UTF-8 -*- i ...
- idea 配置 tomcat 教程
最近在搞一个项目需要用到idea 配置tomcat,翻了翻网上的帖子发现稂莠不齐,最后决定还是自己写个吧!(其实我挺蠢的走了好多的弯路,哎~) 1.首先准备一个需要大家tomcat的工程,然后使用id ...
- 巨杉TechDay回顾 | 技术人的夏天 · 就是这么燃!
在All in Cloud的云计算时代,业务和应用正在不断“云化”,在此过程中云原生(Cloud Native)理念应运而生.作为云化改造的重要部分,云数据库因其天生的弹性扩展能力以及灵活.易用等特点 ...
- ping和tracert
ping命令常用于测试2台主机网络是否连通 TTL的默认值有:64(linux),128(windows),255(路由器) 此例TTL是63所以选用64来减去63等于1,这是说明经过了1个路由器,没 ...
- 傻傻分不清之 Cookie、Session、Token、JWT
傻傻分不清之 Cookie.Session.Token.JWT 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证明“你是你自己”(比如:你每天上下班打卡,都需要通过指纹打 ...
- 剑指offer系列——59/60.按之字形顺序打印二叉树/把二叉树打印成多行
Q:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推. A:BFS,偶数层reverse vector&l ...
- pyodbc 向excel中读写数据
import pyodbc conn_info=( 'DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};''DBQ=[Sh ...
- Web设计精髓(转)
作者:zhouwenqi 地址:http://www.zhouwenqi.com/blog/board_43.html 这篇文章说实际问题的,所以不多强调,下面是我总结的一些比较突出的细节问题,而且 ...