React 组件性能优化探索实践
转自:http://www.tuicool.com/articles/Ar6Zruq
React本身就非常关注性能,其提供的虚拟DOM搭配上Diff算法,实现对DOM操作最小粒度的改变也是非常的高效。然而其组件渲染机制,也决定了在对组件进行更新时还可以进行更细致的优化。
react组件渲染
react的组件渲染分为初始化渲染和更新渲染。
在初始化渲染的时候会调用根组件下的所有组件的render方法进行渲染,如下图(绿色表示已渲染,这一层是没有问题的):
但是当我们要更新某个子组件的时候,如下图的绿色组件(从根组件传递下来应用在绿色组件上的数据发生改变):
我们的理想状态是只调用关键路径上组件的render,如下图:
但是react的默认做法是调用所有组件的render,再对生成的虚拟DOM进行对比,如不变则不进行更新。这样的render和虚拟DOM的对比明显是在浪费,如下图(黄色表示浪费的render和虚拟DOM对比)
那么如何避免发生这个浪费问题呢,这就要牵出我们的 shouldComponentUpdate
shouldComponentUpdate
react在每个组件生命周期更新的时候都会调用一个 shouldComponentUpdate(nextProps, nextState)
函数。它的职责就是返回true或false,true表示需要更新,false表示不需要,默认返回为true,即便你没有显示地定义 shouldComponentUpdate 函数。这就不难解释上面发生的资源浪费了。
为了进一步说明问题,我们再引用一张官网的图来解释,如下图( SCU表示shouldComponentUpdate,绿色表示返回true(需要更新),红色表示返回false(不需要更新);vDOMEq表示虚拟DOM比对,绿色表示一致(不需要更新),红色表示发生改变(需要更新)):
根据渲染流程,首先会判断shouldComponentUpdate(SCU)是否需要更新。如果需要更新,则调用组件的render生成新的虚拟DOM,然后再与旧的虚拟DOM对比(vDOMEq),如果对比一致就不更新,如果对比不同,则根据最小粒度改变去更新DOM;如果SCU不需要更新,则直接保持不变,同时其子元素也保持不变。
C1根节点,绿色SCU (true),表示需要更新,然后vDOMEq红色,表示虚拟DOM不一致,需要更新。
C2节点,红色SCU (false),表示不需要更新,所以C4,C5均不再进行检查
C3节点同C1,需要更新
C6节点,绿色SCU (true),表示需要更新,然后vDOMEq红色,表示虚拟DOM不一致,更新DOM。
C7节点同C2
C8节点,绿色SCU (true),表示需要更新,然后vDOMEq绿色,表示虚拟DOM一致,不更新DOM。
为了避免一定程度的浪费,react官方还在0.14版本中加入了无状态组件,如下:
// es5
function HelloMessage(props) {
return <div>Hello {props.name}</div>;
}
// es6
const HelloMessage = (props) => <div>Hello {props.name}</div>;
具体可参考官网: Reusable Components
既然明白了这关键所在,现在是时候向我们的大大小小一箩筐组件开刀了。
牛刀小试,直接把一些不需要更新的组件返回false
下面我们以音量图标为例,这是一个svg图标,不需要更新,所以直接return false
import React, {Component} from 'react';
class Mic extends Component {
constructor(props) {
super(props);
}
shouldComponentUpdate() {
return false;
}
render() {
return (
<svg className="icon-svg icon-mic" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" aria-labelledby="title">
<title>mic</title>
<path className="path1" d="M15 22c2.761 0 5-2.239 5-5v-12c0-2.761-2.239-5-5-5s-5 2.239-5 5v12c0 2.761 2.239 5 5 5zM22 14v3c0 3.866-3.134 7-7 7s-7-3.134-7-7v-3h-2v3c0 4.632 3.5 8.447 8 8.944v4.056h-4v2h10v-2h-4v-4.056c4.5-0.497 8-4.312 8-8.944v-3h-2z"></path>
</svg>
)
}
} export default Mic;
登堂入室,对数据进行对比确定是否需要更新
先来个官网的例子,通过判断id是否改变来确定是否需要更新:
shouldComponentUpdate: function(nextProps, nextState) {
return nextProps.id !== this.props.id;
}
看起来也没那么玄乎,直接一个 !==
对比下就ok了,那是不是所有的都可以这样直接对比就可以呢? 我们先来看下js的两个数据类型(原始类型与引用类型)的各自比较
// 原始类型var a = 'hello the';var b = a;
b = b + 'world';console.log(a === b); // false// 引用类型var c = ['hello', 'the'];var d = c;
d.push('world');console.log(c === d); // true
我们可以看到a和b不等,但是c和d是一样一样的,这修改了d,也直接修改了c,那还怎么对比(关于原始类型与引用类型的区别这里就不说明了)。
现在看来我们得分情况处理了,原始类型数据和引用类型数据得采用不同的办法处理。
原始类型数据
这没什么好说的,直接比对就是了。但是每个人都是想偷懒的,这要是每个组件都要这样去写下也挺麻烦的,于是react官方有了插件帮我们搞定这事:
PureRenderMixin (es5的插件)
var PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
mixins: [PureRenderMixin], render: function() {
return <div className={this.props.className}>foo</div>;
}
});
Shallow Compare (es6的插件)
var shallowCompare = require('react-addons-shallow-compare');
export class SampleComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
} render() {
return <div className={this.props.className}>foo</div>;
}
}
引用类型数据
既然引用类型数据一直返回true,那就得想办法处理,能不能把前后的数据变成不一样的引用呢,那样不就不相等了吗?于是就有了我们的不可变数据。
react官方提供了一个 Immutability Helpers
const newValue = {
...oldValue // 在这里做你想要的修改};// 快速检查 —— 只要检查引用newValue === oldValue; // false// 如果你愿意也可以用 Object.assign 语法const newValue2 = Object.assign({}, oldValue); newValue2 === oldValue; // false
然后在 shouldComponentUpdate
中进行比对
shouldComponentUpdate(nextProps) { return isObjectEqual(this.props, nextProps);
} 我们目前采用的是在reducer里面更新数据使用Object.assign({}, state, {newkey: newValue}
(数据管理采用redux),然后在组件里面根据某个具体的字段判断是否更新,如title或id等,而不是判断整个对象:
shouldComponentUpdate: function(nextProps, nextState){
return nextProps.title !== this.props.title;
}
React 组件性能优化探索实践的更多相关文章
- React 组件性能优化
React组件性能优化 前言 众所周知,浏览器的重绘和重排版(reflows & repaints)(DOM操作都会引起)才是导致网页性能问题的关键.而React虚拟DOM的目的就是为了减少浏 ...
- React组件性能优化
转自:https://segmentfault.com/a/1190000006100489 React: 一个用于构建用户界面的JAVASCRIPT库. React仅仅专注于UI层:它使用虚拟DOM ...
- React组件性能优化总结
性能优化的思路 影响网页性能最大的因素是浏览器的重排(repaint)和重绘(reflow). React的Virtual DOM就是尽可能地减少浏览器的重排和重绘. 从React渲染过程来看,如何防 ...
- react组件性能优化PureComponent
首先我们使用react组件会配合connect来连接store获取state,那么只要store中的state发生改变组件就会重新渲染,所以性能不高,一般我们可以使用shouldComponentUp ...
- 如何对react进行性能优化
React本身就非常关注性能,其提供的虚拟DOM搭配上DIff算法,实现对DOM操作最小粒度的改变也是非常高效的,然而其组件的渲染机制,也决定了在对组件更新时还可以进行更细致的优化. react组件 ...
- 【读书笔记】读《高性能网站建设指南》及《高性能网站建设进阶指南:Web开发者性能优化最佳实践》
这两本书就一块儿搞了,大多数已经理解,简单做个标记.主要对自己不太了解的地方,做一些记录. 一.读<高性能网站建设指南> 0> 黄金性能法则:只有10%~20%的最终用户响应时间 ...
- 经典的性能优化最佳实践 web性能权威指南 读书笔记
web性能权威指南 page 203 经典的性能优化最佳实践 无论什么网络,也不管所用网络协议是什么版本,所有应用都应该致力于消除或减 少不必要的网络延迟,将需要传输的数据压缩至最少.这两条标准是经典 ...
- React Native 性能优化指南【全网最全,值得收藏】
2020 年谈 React Native,在日新月异的前端圈,可能算比较另类了.文章动笔之前我也犹豫过,但是想到写技术文章又不是赶时髦,啥新潮写啥,所以还是动笔写了这篇 React Native 性能 ...
- React拖拽组件Dragact V0.1.7:教你优化React组件性能与手感
仓库地址:Dragact手感丝滑的拖拽布局组件 预览地址:支持手机端噢- 上回我们说到,Dragact组件已经进行了一系列的性能优化,然而面对大量数据的时候,依旧比较吃力,让我们来看看,优化之前的Dr ...
随机推荐
- MySQL解压版配置步骤
mysql-5.7.14-winx64\bin配置到Path中 在解压路径下复制my-default.ini,修改名称为my.ini 在my.ini添加如下 [mysqld] basedir=C:\\ ...
- mysql中的多行查询结果合并成一个
SELECT GROUP_CONCAT(md.data1) FROM DATA md,contacts cc WHERE md.conskey=cc.id AND md.mimetype_id= 5 ...
- Windows环境下的NodeJS+NPM+Bower安装配置
npm作为一个NodeJS的模块管理,之前我由于没有系统地看资料所以导致安装配置模块的时候走了一大段弯路,所以现在很有必要列出来记录下.我们要先配置npm的全局模块的存放路径以及cache的路径,例如 ...
- zip命令的基本用法
zip命令的基本用法是: zip [参数] [打包后的文件名] [打包的目录路径] linux zip命令参数列表: -a 将文件转成ASCII模式 -F 尝试修复损坏的压缩文件 -h 显示帮助界面 ...
- [转]C# 使用Nlog记录日志到数据库
本文转自:http://www.cnblogs.com/weixing/archive/2013/04/26/3044422.html 摘要]Nlog是一个很不错的.NET日志记录组件,它可以将日志输 ...
- transactionManager 以及datasource type解析
transactionManager 在 MyBatis 中有两种事务管理器类型(也就是 type=”[JDBC|MANAGED]”): JDBC – 这个配置直接简单使用了 JDBC 的提交和回滚设 ...
- HTML 学习笔记 (drag & drop)
拖放(Drag & Drop)是一种常见的特性,即抓取对象以后拖到另一个位置.在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放.过去,我们用监听鼠标的Mousedown.Mouseo ...
- maven/gradle 打包后自动上传到nexus仓库
前提: nexus的相关repository必须设置允许redeploy,参考下图: maven项目: pom.xml中增加以下节点: <distributionManagement> & ...
- [LeetCode] Minimum Number of Arrows to Burst Balloons 最少数量的箭引爆气球
There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided ...
- 【JavaWeb学习】文件的上传和下载
一.文件上传 1.1.概述 实现web开发中的文件上传功能,需完成如下二步操作: 在web页面中添加上传输入项 在servlet中读取上传文件的数据,并保存到本地硬盘中 如何在web页面中添加上传输入 ...