【React系列】一文让你了解React中Component和PureComponent差异之分

news/2025/10/21 8:23:52/文章来源:https://www.cnblogs.com/Dsir/p/19154059

关于React中Component和PureComponent 你应该了解的

任何技术和产品产生的时候,都应该了解当时所处的场景,以及为什么会需要这个东西,他是来解决当下业务线那些弊端,又或者优化了什么,否则它的产生将毫无意义可言。

关于源码是处于ReactBaseClasses这个文件:

    import {Component, PureComponent} from './ReactBaseClasses';

进入一一剖析里面所含的技术要点,以及为什么会需要这个东西,以及使用场景,

Component

function Component(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;// We initialize the default updater but the real one gets injected by the// renderer.this.updater = updater || ReactNoopUpdateQueue;
}Component.prototype.isReactComponent = {};
/*** @param {object|function} partialState Next partial state or function to*        produce next partial state to be merged with current state.* @param {?function} callback Called after state is updated.* @final* @protected*/
Component.prototype.setState = function(partialState, callback) {if (typeof partialState !== 'object' &&typeof partialState !== 'function' &&partialState != null) {throw new Error('setState(...): takes an object of state variables to update or a ' +'function which returns an object of state variables.',);}this.updater.enqueueSetState(this, partialState, callback, 'setState');
};/*** Forces an update. This should only be invoked when it is known with* certainty that we are **not** in a DOM transaction.** You may want to call this when you know that some deeper aspect of the* component's state has changed but `setState` was not called.** This will not invoke `shouldComponentUpdate`, but it will invoke* `componentWillUpdate` and `componentDidUpdate`.** @param {?function} callback Called after update is complete.* @final* @protected*/
Component.prototype.forceUpdate = function(callback) {this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};

上述源码可以得知:

  1. 创建了一个 Component的构造函数,并在其内部定义了 props context refs updater四个私有属性。
  2. 接着在其原型对象上定义了 isReactComponent对象,setState方法,forceUpdate方法
  3. 然后,我们在项目中使用es6的class类的继承来创建了react组件,如下:
import React, { Component, memo } from 'react'class Test extends Component<any, any> {constructor(props) {super(props)}render() {console.log(this)return <div>ReadcowPuch</div>}
}export default ReadcowPuch
  1. 因为我们在创建自定义的组件时继承了 react.Component, 所以 我们可以在我们所创建的组件中使用 Component构造函数 原型对象上的方法和属性。(f12)打开开发者就能找到对应的属性和方法.

PureComponent

当使用component时,父组件的state或prop更新时,无论子组件的state、prop是否更新,都会触发子组件的更新,这会形成很多没必要的render,浪费很多性能;
pureComponent的优点在于:pureComponent在shouldComponentUpdate只进行浅层的比较,只要外层对象没变化,就不会触发render,减少了不必要的render,当遇到复杂数据结构时,可以将一个组件拆分成多个pureComponent,以这种方式来实现复杂数据结构,以期达到节省不必要渲染的目的,
如:表单、复杂列表、文本域等情况;不需要开发者使用shouldComponentUpdate就可使用简单的判断来提升性能;由于进行的是浅比较,可能由于深层的数据不一致导致而产生错误的否定判断,从而导致页面得不到更新;主要在于pureComponent可以减少不必要的render,从而提高了性能,另外就是,不需要再手写shouldComponentUpdate里面的代码,从而节省了代码量;当组件更新时,pureComponent的shouldComponentUpdate函数里对props和state做了一个浅对比,如果组件的state和prop都没有发生变化,就不会触发render方法,省去了virtual DOM的diff和重新生成的过程,从而提升了性能;也正是因为是浅对比,所以不适合使用在含有多层嵌套对象的state和prop中。
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.
assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;export {Component, PureComponent};

从上面源码,我们可以看到:
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy()) 此处没有直接继承Component,是为了避免继承 Component 的Constructor方法。目的是为了 减少一些内存的使用。
Object.assign(pureComponentPrototype, Component.prototype)此处做了优化 把 Component.prototype属性浅拷贝到pureComponentPrototype上 防止原型连拉长 导致方法的多层寻找 减少查询次数
最后增加了 isPureReactComponent 属性,用来区分Component组件还是PureComponent

关于这里的assign方法,react 团队进行了单独封装成一个js文件,但本质还是调用Object.assign方法,

在一个组件从创建到展现到游览器,途中是要进行很多步骤,dom tree的渲染,css 等等的加载过程,在用PureComponent创建对应的组件,就是来优化组件,通过减少不必要的更新,进而提升性能。其每次更新时会自动的对更新前后的props和state进行一个简单的对比,来决定是否进行更新。进行的是浅比较。

1.浅比较也称引用相等,在javascript中, ===是作浅比较,只检查左右两边是否是同一个对象的引用,作为值类型,和引用类型地址值之间的比较。来判定是否有对等关系。
2.深比较也称原值相等,深比较是指检查两个对象的所有属性是否都相等,深比较需要以递归的方式遍历两个对象的所有属性,操作比较耗时,深比较不管这两个对象是不是同一对象的引用

type shallowEqual = (objA:any,objB:any) => boolean; // 浅比较type is = (a:any,b:any) => boolean; // type 声明函数约束type deepEqual = (objA:any,objB:any) => boolean; // 深比较const is:is = (a:any,b:any) => {return (a === b && (a !==0 || 1/a === 1/b)) || (a !== b && a !== b);
}
//浅比较
const shallowEqual:shallowEqual = (objA,objB) =>{if(is(objA,objB)){return true;}if(typeof objA !== 'object' ||  objA === null ||typeof objB !== 'object' ||  objB === null ){return false;}const keysA = Object.keys(objA) // 获取keyconst keysB = Object.keys(objB) if(keysA.length !== keysB.length){return false;}for (let i = 0; i < keysA.length; i++) {const currentKey = keysA[i];if(!Object.prototype.hasOwnProperty.call(objB,currentKey) ||!is(objA[currentKey],objB[currentKey])){return false;}}return true;
}// 深比较
const deepEqual:deepEqual = (objA,objB) => {// 判断是否NaN 类型if(Number.isNaN(objA) && Number.isNaN(objB)) return true;// 是否为对象let IsObj = (val:any) => typeof val === 'object' && val !== null;if(!IsObj(objA) || !IsObj(objB)) return objA === objB;if(objA === objB) return true;// 执行到这objA,objB 都是对象,为了区分 {} 和 [],如果没有此判断,会导致 deepEquals({}, []) 返回 true let isEmptyObj = (Array.isArray(objA) && !Array.isArray(objB) || Array.isArray(objB) && !Array.isArray(objA)) ;if(isEmptyObj) return false;// 获取键的长度,长度不等则不同,对数据进行遍历进行对比if (Object.keys(objA).length !== Object.keys(objB).length) return false;for (let key in objA) {if (objA.hasOwnProperty(key)) {const isEqual = deepEqual(objA[key], objB[key])if (!isEqual)  return isEqual;}}return true;
}console.log(deepEqual(0, 0));	// true
console.log(deepEqual('str', 'str'));	// true
console.log(deepEqual(true, true));	// true
console.log(deepEqual(undefined, undefined));	// true
console.log(deepEqual(null, null));	// true
console.log(deepEqual({}, {}));	// true
console.log(deepEqual({val: 1}, {val: 1}));	// true
console.log(deepEqual([1,2,3], [1,2,3]));	// true
console.log(deepEqual([1,2,{a: 1}], [1,2,{a: 1}]));	// true

3.PureComponent的浅比较源码中主要用的是 shallowEqual,而在该方法内部主要是利用了 Object.is() code

关于源码当中使用的Object.is方法

以下是ECMAScript® 2023 Language Specification 对于该方法的一些概述:

20.1.2.14 Object.is ( value1, value2 )

When the is function is called with arguments value1 and value2, the following steps are taken:

Return SameValue(value1, value2).

对于源码的一些改动(ts写法):

    type is = (a:any,b:any) => boolean; // type 声明函数约束const is:is = (a:any,b:any) => {return (a === b && (a !==0 || 1/a === 1/b)) || (a !== b && a !== b);}const ObjectIs : (x:any,y:any) => boolean  = typeof Object.is === 'function' ? Object.is : is;

注意点tips:

// Case 1: Evaluation result is the same as using ===
Object.is(25, 25);                // true
Object.is('foo', 'foo');          // true
Object.is('foo', 'bar');          // false
Object.is(null, null);            // true
Object.is(undefined, undefined);  // true
Object.is(window, window);        // true
Object.is([], []);                // false
var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo);              // true
Object.is(foo, bar);              // false
// Case 2: Signed zero
Object.is(0, -0);                 // false
Object.is(+0, -0);                // false
Object.is(-0, -0);                // true
Object.is(0n, -0n);               // true
// Case 3: NaN
Object.is(NaN, 0/0);              // true
Object.is(NaN, Number.NaN)        // true

源码链接地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/941911.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DIY ChatGPT 一周狂揽 27k Star「GitHub 热点速览」

上周,腾讯、阿里、蚂蚁到谷歌、Anthropic,各大厂都跟约好了一样,在 AI 各个领域疯狂“亮剑”。咱们吃瓜群众围观“神仙打架”的同时,开源社区也没闲着。抛开那些高大上的大模型不谈,GitHub 上的“野生”开源大神们…

Active Directory安全技巧:FSMO角色管理与PowerShell查询

本文详细介绍了Active Directory中FSMO角色的重要性,提供了使用PowerShell查询森林和域中FSMO角色持有者的具体代码,帮助系统管理员更好地管理域控制器备份和安全策略。Active Directory安全技巧第10篇:FSMO角色 获…

Random VIMs

Random VIMs 设置缩进 :set ts=4 sw=4 sts=4设置相对行号 :set relativenumber本文来自博客园,作者:CuteNess,转载请注明原文链接:https://www.cnblogs.com/CuteNess/p/19154054

【React系列】React.memo() vs useMemo()

React.memo()与useMemo()之间有什么主要区别? 性能优化是一只web开发中的一个重要讨论点。对于react团队同样如此,为了实现加速组件的渲染速度,采用“备忘录”的方式。 所以这个时候就React.memo()和 useMemo 钩子 …

【每日积累】javascript 一文弄懂eval

eval 动态化执行语句 概述 eval方法是javascript的全局方法,能够执行含有javascript代码的字符串,虽然eval方法带来强大的动态执行功能,但考虑其负面影响,建议少用,在特殊情况下可以使用eval方法动态改变代码的执…

腾讯云COS通过CDN加速配置指南 - 教程

腾讯云COS通过CDN加速配置指南 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mona…

前端: 如何优化列表大批量的数据渲染

需求点:如何列表数据渲染进行优化? 最近业务上也碰到这个问题点。上网也查了查资料,貌似也经常问,特此写文章记录下来。关于如何处理以上上面的业务痛点: 就两点: 1 、虚拟列表是最主流的解决方案,不渲染所有的…

量子计算25年发展历程与技术挑战

本文回顾了量子信息处理会议25年发展历程,探讨了量子计算从理论到实验的突破,包括量子算法实现、量子复杂性理论对数学的影响,以及当前面临的可扩展性、错误率控制和实际应用等关键技术挑战。25年量子信息处理发展历…

tomcat启动一次问题的处理。

tomcat启动一次问题的处理。说明:2025.10.20,出现启动tomcat对任何请求都没有响应的情况。通过删除 $tomcat/work/Catalina 下的全部数据。并重启解决。但是重启需要的时间比较久。大约5分钟。

软件开发 --- trae如何和环境配合执行

软件开发 --- trae如何和环境配合执行trae会自动执行代码,但是执行前需要我们提前安装好所有的执行环境。 有的环境可能需要手动配合,比如trae在执行这个代码前手动触发环境执行。

marmot的一些特点

marmot的一些特点以前简单介绍过marmot ,以下说下一些特点 特点当前版本已经通过nats server 包内置到了服务中,不需要独立部署nats 了,但是推荐还是部署3个节点 默认内置的nats 没有开启认证,注意使用,同时nats …

应用安全 --- 如何反编译一个超大的函数

应用安全 --- 如何反编译一个超大的函数先用ida反编译一下 再用claude max 完善代码并配合完整的提示词 再次执行上述过程直到没有任何遗漏的代码

藏宝阁

书籍轻松主义★★★★☆反脆弱★★★★★娱乐至死★★★★☆动物庄园★★★★★谈谈方法★★★★☆小说雪中悍刀行★★★★★剑来★★★★★斗破苍穹★★★★★完美世界★★★★★武动乾坤★★★☆☆我在精神病院学斩神…

【模块化解读】commonjs vs commonjs2 exports vs module.exports

背景 最近在用typescript写工具库的时候,无意中在 webpack中看到了两个关键字,commonjs 和 commonjs2. 瞬间产生了好奇。后面看了issues才得知它们与模块化 导出有着密切关系。 CommonJs spec defines only exports.…

【GitHub每日速递 251021】一键将全新Arch安装变身超美现代Web开发系统!Omarchy太神了

原文: https://mp.weixin.qq.com/s/aE_bPqSXRQxxH7zq_4HYIQ 一键将全新Arch安装变身超美现代Web开发系统!Omarchy太神了 omarchy 是一个基于 Arch Linux 和 Hyprland 桌面环境的自动化配置工具。简单讲,它是一套预设…

[Mongodb]mongodb的安装以及增删改查

mongodb的安装 mongo主页 下载完成之后将目录放置下方 /usr/local/安装之后就配置环境变量: vim ~/.bash_profile下方是我自己的环境变量配置 # JDK_HOMEJAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_321.j…

PHP 8.5 新特性 闭包可以作为常量表达式了

PHP 8.5 新特性 闭包可以作为常量表达式了 PHP 8.5 又带来了一个让人兴奋的新特性:闭包现在可以作为常量表达式使用了,这意味着它们可以出现在默认参数或属性值中。 你是不是也遇到过这种情况:想在 PHP 中把闭包设置为…

【JavaScript-基础】split,splice,slice 三者的用法

split,splice,slice 三者的用法 很多知识点不熟悉可以自行去下面链接查询: mdn web docs 最近一直忙于搞python,等后续有时间更新python相关的内容。毕竟现在在弄web.有些知识点需要巩固,以便自己后续带人和巩固自己…

2025 代码源 CSP-S 模拟赛复盘

Day 16 T1 双重心 分类讨论一下:是原树的双重心之一,考虑把这条边割掉,接到另一个连通块的任意一个点上都是可行的。 不割掉原树上的双重心的边,两侧的连通块内的的任意一条边可以断开,连通块内相互连边就行。 考…

2025.10.21——1绿

普及+/提高 P1347 排序 wpmx昨晚写的有意思的题,数据范围比较小,我就直接用set+m次拓扑排序,30min写出来,要注意输出顺序后的句号,以及特判n==1