[react]10、react性能优化

1、列表&key

一、React更新流程

React在props或state发生改变时,会调用React的render方法,会创建一颗不同的树。React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI。

  • 同层节点之间相互比较,不会垮节点比较;
  • 不同类型的节点,产生不同的树结构;
  • 开发中,可以通过key来指定哪些节点在不同的渲染下保持稳定;

1、对比不同类型的元素
当节点为不同的元素,React会拆卸原有的树,并且建立起新的树

<div><Child />
</div>
~~~~~~~~~~~
<span><Child />
</span>

2、对比同一类型的元素
当比对两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性
1)、React 知道只需要修改 DOM 元素上的 className 属性

<div classname="before" title="stuff" />
<div classname="after" title="stuff" />

2)、当更新 style 属性时,React 仅更新有所更变的属性

<div style={{ color: 'red', fontWeight: 'bold' }} />
<div style={{ color: 'green', fontWeight: 'bold' }} />

3)、同类型的组件元素
组件会保持不变,React会更新该组件的props,并且调用componentWillReceiveProps() 和 componentWillUpdate() 方

3、对子节点进行递归
在默认条件下,当递归 DOM 节点的子元素时,React 会同 时遍历两个子元素的列表;当产生差异时,生成一个 mutation。
1)、在最后插入一条数据的情况,前面两个比较是完全相同的,所以不会产生mutation,最后一个比较,产生一个mutation,将其插入到新的 DOM树中即可;

<ul><li>first</li><li>second</li>
</ul>
~~~~~~~~~
<ul><li>first</li><li>second</li><li>third</li>
</ul>

最后一次插入third,只会产生一个mutation
2)、如果我们是在中间插入一条数据
React会对每一个子元素产生一个mutation,这种低效的比较方式会带来一定的性能问题

<ul><li>first</li><li>second</li>
</ul>
~~~~~~~~~
<ul><li>zero</li><li>first</li><li>second</li>
</ul>

在第一次插入zero,后面first、second都会产生mutation。

二、keys的优化

我们在前面遍历列表时,总是会提示一个警告,让我们加入一个key属性

  • 在最后位置插入数据,这种情况,有无key意义并不大
  • 在前面插入数据,这种做法,在没有key的情况下,所有的li都需要进行修改
  • 当子元素(这里的li)拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素
    key的注意事项:
    1)、key应该是唯一的;
    2)、key不要使用随机数(随机数在下一次render时,会重新生成一个数字);
    3)、使用index作为key,对性能是没有优化的;

2、 shouldComponentUpdate

在render调用之前会调用shouldComponentUpdate,不建议在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能。
该方法有两个参数:

  • nextProps 修改之后,最新的props属性
  • nextState 修改之后,最新的state属性

该方法返回值是一个boolean类型

  • 返回值为true(默认返回true),那么就需要调用render方法
  • 返回值为false,那么就不需要调用render方法
shouldComponentUpdate(nextProps, nextState) {if (this.state.counter !== nextState.counter) {return true;}return false;
}

源码分析

// react-reconciler/src/forks/ReactFiberClassComponent.new.js Line 291
function checkShouldComponentUpdate(workInProgress,ctor,oldProps,newProps,oldState,newState,nextContext,
) {const instance = workInProgress.stateNode;if (typeof instance.shouldComponentUpdate === 'function') { // 判断instance有无shouldComponentUpdate方法const shouldUpdate = instance.shouldComponentUpdate(newProps,newState,nextContext,);return shouldUpdate;}// 如果isPureReactComponent=true就会进行浅层比较if (ctor.prototype && ctor.prototype.isPureReactComponent) {return (!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState));}return true;
}

3、PureComponent

React.PureComponentReact.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。

import React, { Component, PureComponent } from 'react'
// header
class Header extends PureComponent {render() {console.log('App Header被调用')return (<h2>我是Header组件</h2>)}
}export class App extends PureComponent {constructor(props) {super(props);this.state = {counter: 0}}render() {console.log('App 被调用')return (<div><h2>{"当前计数:" + this.state.counter}</h2><button onClick={e => this.increment()}>+1</button><Header/></div>)}increment () {this.setState({counter: this.state.counter + 1})}
}
export default App

源码分析

PureComponent源码

// react/src/ReactBaseClasses.js Line 129
/*** 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);
// isPureReactComponent标记为true
pureComponentPrototype.isPureReactComponent = true; export {Component, PureComponent};

shallowEqual源码

// shared/shallowEqual
/*** Performs equality by iterating through keys on an object and returning false* when any key has values which are not strictly equal between the arguments.* Returns true when the values of all keys are strictly equal.*/
function shallowEqual(objA: mixed, objB: mixed): boolean {if (is(objA, objB)) { // 如果是同一个对象,直接返回truereturn 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;}// Test for A's keys different from B.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;
}

4、memo

React.memo 为高阶组件。
如果组件在相同 props 的情况下渲染相同的结果,那么可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useStateuseReduceruseContext 的 Hook,当 state 或 context 发生变化时,它仍会重新渲染。
默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现

function MyComponent(props) {/* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {/*如果把 nextProps 传入 render 方法的返回结果与将 prevProps 传入 render 方法的返回结果一致则返回 true,否则返回 false*/
}
export default React.memo(MyComponent, areEqual);

源码分析

memo函数入口

// react/src/ReactMemo.js Line 12
export function memo<Props>(type: React$ElementType,compare?: (oldProps: Props, newProps: Props) => boolean,
) {// 调用compare方法const elementType = {$$typeof: REACT_MEMO_TYPE, // memo函数的标志type,compare: compare === undefined ? null : compare,};return elementType;
}

updateMemoComponent:使用memo函数实现的类会调用此函数

// react-reconciler/src/forks/ReactFiberBeginWork.new.js Line 384
function updateMemoComponent(current: Fiber | null,workInProgress: Fiber,Component: any,nextProps: any,updateLanes: Lanes,renderLanes: Lanes,
): null | Fiber {if (current === null) {const type = Component.type;if (isSimpleFunctionComponent(type) &&Component.compare === null &&// SimpleMemoComponent codepath doesn't resolve outer props either.Component.defaultProps === undefined) {let resolvedType = type;// If this is a plain function component without default props,// and with only the default shallow comparison, we upgrade it// to a SimpleMemoComponent to allow fast path updates.workInProgress.tag = SimpleMemoComponent;workInProgress.type = resolvedType;return updateSimpleMemoComponent(current,workInProgress,resolvedType,nextProps,updateLanes,renderLanes,);}const child = createFiberFromTypeAndProps(Component.type,null,nextProps,workInProgress,workInProgress.mode,renderLanes,);child.ref = workInProgress.ref;child.return = workInProgress;workInProgress.child = child;return child;}const currentChild = ((current.child: any): Fiber); // This is always exactly one childif (!includesSomeLane(updateLanes, renderLanes)) {// This will be the props with resolved defaultProps,// unlike current.memoizedProps which will be the unresolved ones.const prevProps = currentChild.memoizedProps;// Default to shallow comparison// 判断compare是否存在,决定使用compare还是shallowEquallet compare = Component.compare;compare = compare !== null ? compare : shallowEqual;if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);}}// React DevTools reads this flag.workInProgress.flags |= PerformedWork;const newChild = createWorkInProgress(currentChild, nextProps);newChild.ref = workInProgress.ref;newChild.return = workInProgress;workInProgress.child = newChild;return newChild;
}


喜欢的朋友记得点赞、收藏、关注哦!!!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

基础网络安全知识

1.ctfhub技能树 1.1 Web-SQL注入 Web-SQL注入-整数型 && 字符型 && MySQL结构 参考&#xff1a;5.9.6MySql注入 Web-SQL注入-报错注入 step1: 查库名 ?id1 and extractvalue(1,concat(0x7e,database(),0x7e))-- step2: 查看表名 ?id1 and extractvalue(1…

一、初识C语言(1)

1.C语言识别的是二进制语言 C语言是一门计算机语言&#xff0c;计算机是硬件&#xff0c;硬件分通电&#xff08;1&#xff09;和 未通电&#xff08;0&#xff09;两种情况&#xff0c;所以C语言识别的都是0 / 1信号&#xff0c;也就是二进制语言。 2.C语言文件类型以及基本框…

传输协议设计与牧村摆动(Makimoto‘s Wave)

有一条活鱼和一条死鱼&#xff0c;你准备怎么做&#xff0c;你会将活鱼红烧或将死鱼清蒸吗&#xff1f;好的食材只需要最简单的烹饪&#xff0c;不好的食材才需要花活儿。 我此前的文字几乎都在阐述一个观点&#xff0c;广域网就是那条死鱼&#xff0c;数据中心则是那条活鱼。…

80后聊架构:架构设计中两个重要指标,延时与吞吐量(Latency vs Throughput) | 架构师之路...

《架构师之路&#xff1a;架构设计中的100个知识点》 3.延时与吞吐量 有朋友问我说&#xff0c;架构优化时&#xff0c;什么时候要重点优化延时&#xff0c;什么时候要重点优化吞吐量&#xff1f; 画外音&#xff1a;补充阅读材料在最后。 延时&#xff08;Latency&#xff09;…

全星魅-物联网定位终端-北斗定位便携终端-北斗有源终端

在当今快速发展的物流运输行业中&#xff0c;精准定位与实时监控已成为确保货物安全与高效运输的关键因素。为了满足这一需求&#xff0c;QMCZ10作为一款集4G&#xff08;LTE Cat1&#xff09;通讯技术与智能定位功能于一体的终端产品&#xff0c;应运而生。它不仅具备普通定位…

网络编程(一):UDP socket api => DatagramSocket DatagramPacket

目录 1. TCP 和 UDP 1.1 TCP / UDP 的区别 1.1.1 有连接 vs 无连接 1.1.2 可靠传输 vs 不可靠传输 1.1.3 面向字节流 vs 面向数据报 1.1.4 全双工 vs 半双工 2. UDP socket api 2.1 DatagramSocket 2.1.1 构造方法 2.1.2 receive / send / close 2.2 DatagramPacket …

JDBC入门

什么是JDBC JDBC&#xff08;Java DataBase Connectivity&#xff09;就是Java数据库连接&#xff0c;说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库&#xff0c;JDBC是用Java语言向数据库发送SQL语句。 使用JDBC 使用JDBC会用到它…

ReactPress:深入解析技术方案设计与源码

ReactPress Github项目地址&#xff1a;https://github.com/fecommunity/reactpress 欢迎提出宝贵的建议&#xff0c;欢迎一起共建&#xff0c;感谢Star。 ReactPress是一个基于React框架开发的开源发布平台&#xff0c;它不仅仅是一个简单的博客系统&#xff0c;更是一个功能全…

Linux挖矿病毒(kswapd0进程使cpu爆满)

一、摘要 事情起因:有台测试服务器很久没用了&#xff0c;突然监控到CPU飙到了95以上&#xff0c;并且阿里云服务器厂商还发送了通知消息&#xff0c;【阿里云】尊敬的xxh: 经检测您的阿里云服务&#xff08;ECS实例&#xff09;i-xxx存在挖矿活动。因此很明确服务器中挖矿病毒…

Stable Diffusion LoRA, LyCoris

本节内容&#xff0c;给大家带来的是stable diffusion的LoRA与LyCoris模型课程。我们在上节课程中&#xff0c;已经详细讲解了关于大模型的使用。在stable diffusion中打造一个大模型&#xff0c;需要基于大量特定特征的图像集进行训练&#xff0c;我们通常将这个过程称之为Dre…

[RoarCTF 2019]Easy Calc 1

[RoarCTF 2019]Easy Calc 1 审题 题目就是一个计算器。 看到源代码有 calc.php 进入看到waf的源代码 知识点 RCE 解题 审核代码 <?php error_reporting(0); if(!isset($_GET[num])){show_source(__FILE__); }else{$str $_GET[num];$blacklist [ , \t, \r, \n,\, &q…

文本转SQL(Text-to-SQL),场景介绍与 Spring AI 实现

在众多的 AI 大模型的应用场景中&#xff0c;Text-to-SQL&#xff0c;也就是文本转 SQL&#xff0c;是其中实用性很高的一个。Text-to-SQL 充分利用了大模型的优势&#xff0c;把用户提供的自然语言描述转换成 SQL 语句&#xff0c;还可以执行生成的 SQL 语句&#xff0c;再把查…

Oracle 23AI创建示例库

一、示例库介绍 多年来&#xff0c;Oracle 一直使用简单的数据库模式 SCOTT 及其两个突出的表 EMP 和 DEPT&#xff0c;用于文档和培训中的各种示例。但不少小伙伴并不知道如何创建这些示例数据&#xff0c;其实Oracle官方上就有提供对应的方法&#xff0c;本文就带领大家完成…

默认 iOS 设置使已锁定的 iPhone 容易受到攻击

苹果威胁研究的八个要点 苹果手机间谍软件问题日益严重 了解 Apple 苹果的设备和服务器基础模型发布 尽管人们普遍认为锁定的 iPhone 是安全的&#xff0c;但 iOS 中的默认设置可能会让用户面临严重的隐私和安全风险。 安全研究员 Lambros 通过Pen Test Partners透露&#…

微博舆情分析:使用Python进行深度解析

目录 一、准备工作 二、基础理论知识 三、步骤详解 数据预处理 情感分析 关键词提取 四、案例分享 数据爬取 数据分析 五、优化 六、结论 在当今信息爆炸的时代&#xff0c;社交媒体平台如微博已成为公众表达意见和情感的重要渠道。微博舆情分析通过对大量微博数据进…

Unet++改进3:添加NAMAttention注意力机制

本文内容:添加NAMAttention注意力机制 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 识别不太显著的特征是模型压缩的关键。然而,它在革命性的注意机制中尚未得到研究。在这项工作中,我们提出了一种新的基于归一化的注意力模块(NAM),它抑制了较不显著…

潮玩宇宙方块兽系统开发:可定制UI与多种游戏内嵌助力个性化体验

潮玩宇宙方块兽系统开发正在推动潮玩与游戏的融合&#xff0c;通过个性化的UI设计和多游戏内嵌模式&#xff0c;为用户带来了独一无二的体验。本文将从可定制UI、多游戏内嵌功能以及系统实现等方面入手&#xff0c;探讨如何构建一个极具吸引力的潮玩宇宙方块兽系统。 一、可定制…

利用亚马逊AWS IoT核心和MQTT进行数据采集的综合指南

论文标题&#xff1a;A Comprehensive Guide on Data Acquisition Utilizing Amazon AWS IOT Core and MQTT 中文标题&#xff1a;利用亚马逊AWS IoT核心和MQTT进行数据采集的综合指南 作者信息&#xff1a; Tanishq. I. KohliPradip R. Selokar 两位作者均来自印度那格浦尔…

高校宿舍信息管理系统小程序

作者主页&#xff1a;编程千纸鹤 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参…

一篇文章入门docker!

文章目录 DockerUbuntu 下 docker 安装安装docker运行docker Docker的常用命令帮助命令镜像命令容器命令其他常用命令小结 分层理解一、Docker镜像的分层结构二、UnionFS与镜像分层三、镜像层的具体内容四、镜像分层的好处五、容器层与镜像层的关系 如何提交一个自己的镜像 Doc…