React是一个专注于UI层的框架,它使用虚拟DOM技术,以保证它UI的高速渲染;使用单向数据流,因此它数据绑定更加简单;那么它内部是如何保持简单高效的UI渲染呢?这种渲染机制有可能存在什么性能问题呢?

原文链接120

React组件渲染问题引出

React不直接操作DOM,它在内存中维护一个快速响应的DOM描述,render方法返回一个DOM的描述,React能够计算出两个DOM描述的差异,然后更新浏览器中的DOM。这就是著名的DOM Diff

就是说React在接收到属性(props)或者状态(state)更新时,就会通过前面的方式更新UI。所以React整个UI渲染是比较快的。但是这里面可能出现的问题是:

假设我们定义一个父组件,其包含了5000个子组件。我们有一个输入框输入操作,每次输入一个数字,对应的那个子组件背景色变红。

<Components>
<Components-1 />
<Components-2 />
<Components-3 />
...
<Components-5000 />
</Components>

这样我们输入数字1,则子组件1背景色变化,但是在这个过程中,所有的子组件都进行了重新渲染,导致整体渲染变慢。造成这种现象的原因是 React中父组件更新默认触发所有子组件更新。(具体例子见文章后demo链接)

同时,我们经常在遍历列表元素时候会遇到这样的提示:

Warning: Each child in an array or iterator should have a unique "key" prop.

这就是我们今天要讨论的两个性能优化点:

  1. 父组件更新默认触发所有子组件更新
  2. 列表类型的组件默认更新方式非常复杂

React性能检测工具

我们利用 react-addons-perf 进行性能检测。引入方法如下:

import Perf from 'react-addons-perf'
window.Perf = Perf // 挂载到全局变量方便使用

检测方法,在浏览器控制台输入如下命令:

  • 开始记录:Perf.start()
  • 结束记录:Perf.stop()
  • 打印结果:printInclusive()

控制台会以表格的形式展示出结果:

上图记录了每个组件的执行耗时,渲染次数等关键信息。我们可以有针对性的进行优化。

注意:生产环境不要引入Perf

React 性能优化原理

这是React官网对组件渲染机制的描述图,其中绿色组件代表不需要更新,红色组件需要更新,影响更新的条件主要有SCU(shouldComponentUpdate)及DOM DIff结果。

我们再来看看 组件触发更新的流程图

通过上述流程图,再对比渲染的图解可以看到,React的性能瓶颈主要出现在生成DOM及DOM Diff的过程。如果进行性能优化,关键在:

  • shouldComponentUpdate 阶段判断,如果属性及状态与上一次相同,这个时候很明显UI不会变化,也不需要执行后续生成DOM,DOM Diff的过程了,可以提高性能。
  • DOM Diff 阶段优化,提高Diff的效率

如何提高组件的渲染效率

针对文章开头提出的两个性能问题,我们得到以下解决方案:

  • 子组件执行 shouldComponentUpdate 方法,自行决定是否更新
  • 给列表中的组件添加key属性

我们可以通过控制子组件的 shouldComponentUpdate 从而控制是否渲染:

// 接收两个参数,分别为待更新的属性及状态值
shouldComponentUpdate(nextProps, nextState) {
// 如果当前的value值与待更新不相等,才执行更新
return this.props.value !== nextProps.value;
}

针对列表遍历类型,遍历时候增加唯一 key 属性值,对子组件进行唯一性识别,准确知道要操作的子组件,提高 DOM Diff 的效率。

array.map(val, key) => {
return <span key={key}>{val}</span>
})

PureRenderMixin 与 PureComponent

为了提高React组件渲染性能,React 针对组件的 shouldComponentUpdate 方法进行了封装处理,我们不需要在每个组件里面手动编写 shouldComponentUpdate

PureRenderMixin

React在之前版本提供了 PureRenderMixin 的mixin形式,其用法如下:

// react官方demo
import PureRenderMixin from 'react-addons-pure-render-mixin';
class FooComponent extends React.Component {
constructor(props) {
super(props);
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
}

其原理就是重写了 shouldComponentUpdate 方法。

PureComponent

React 15.3.0 新增了一个 PureComponent 类,以 ES2015 class 的方式方便地定义纯组件 (pure component),用于取代之前的 PureRenderMixin

这个类的用法很简单,如果你有些组件是纯组件,那么把继承类从 Component 换成 PureComponent 即可。当组件更新时,如果组件的 props 和 state 都没发生改变,render 方法就不会触发,省去 Virtual DOM 的生成和比对过程,达到提升性能的目的。

import React, { PureComponent } from 'react'

class Example extends PureComponent {
render() {
// ...
}
}

这里要注意的是:PureRenderMixin、PureComponent 内进行的仅仅是浅比较对象(shallowCompare)。如果对象包含了复杂的数据结构,深层次的差异可能会产生误判。比如,如果我们的state变为:

state = {
value: { foo: 'bar' }
} // 每次更改value值的时候进行:
this.setState({ value: newValue });

此时直接通过值的比较是行不通的,因为对象的引用关系,导致在子组件里面接受到的 this.props.value 与 nextProps.value 永远都是相等的。这里的解决方案主要有:

  • 深比较: 原理与深拷贝类似,比较耗时,不推荐
  • immutable.js:FaceBook官方提出的不可变数据解决方案,主要解决了复杂数据在deepClone和对比过程中性能损耗

总结

虽然React提供了Virtual DOM DOM Diff 等优秀的能力来提高渲染性能,但是在实际使用过程中,我们经常会遇到父组件更新,不需要更新所以子组件的场景(分页),此时必须考虑利用React本周的渲染机制来进行优化。

React组件性能调优的更多相关文章

  1. React如何性能调优

    一. 二.调优例子 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&q ...

  2. HDFS组件性能调优:数据平衡

    生产系统中什么情况下会添加一个节点呢? 1 增加存储能力 disk 2 增加计算能力 cpu mem 如果增加是的是存储能力,说明存储已接近饱和或者说过段时间就会没有剩余的空间给作业来用.新加的节点存 ...

  3. 小程序组件化框架 WePY 在性能调优上做出的探究

    作者:龚澄 导语 性能调优是一个亘古不变的话题,无论是在传统H5上还是小程序中.因为实现机制不同,可能导致传统H5中的某些优化方式在小程序上并不适用.因此必须另开辟蹊径找出适合小程序的调估方式. 本文 ...

  4. React 性能调优总结

    React 性能调优总结 首先要说一个库: why-did-you-update, 地址:why-did-you-update, 利用这个库可以在页面上快速看到多余渲染的问题: 因为多数情况下我们在R ...

  5. web前端性能调优

    最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...

  6. sqlserver性能调优第一步

    相信不少的朋友,无论是做开发.架构的,还是DBA等,都经常听说“调优”这个词.说起“调优”,可能会让很多技术人员心头激情澎湃,也可能会让很多人感觉苦恼,不知道如何入手.当然,也有很多人对此不屑一顾,因 ...

  7. Advacned Puppet: Puppet Master性能调优

    本文是Advanced Puppet系列的第一篇:Puppet master性能调优,谈一谈如何优化和提高C/S架构下master端的性能. 故事情节往往惊人地类似:你是一名使用Puppet管理线上业 ...

  8. .NET性能调优之一:ANTS Performance Profiler的使用

    .NET性能调优系列文章 系列文章索引 .NET性能调优之一:ANTS Performance Profiler的使用 .NET性能调优之二:使用Visual Studio进行代码度量 .NET性能调 ...

  9. linux概念之性能调优

    目前,对系统进行性能调试的工具有很多,这些可以两大类:一类是标准的分析工具,即所有的UNIX都会带的分析工具: 另一类是不同厂商的UNIX所特有的性能分析工具,比如HP-UX就有自己的增值性能分析工具 ...

随机推荐

  1. angular 组件学习-组件内属性绑定

    #组件内的属性(元素的属性)绑定(property binding) 应用场景:通过改变DOM元素的属性,动态显示/隐藏一个元素 知识点:HTML 属性与DOM属性的区别 改变HTMl属性,浏览器需要 ...

  2. uiautomatorviewer工具的安装与使用

    Android自动化测试应用<一><uiautomatorviewer工具的安装与使用> OldKe 关注 2018.01.25 18:00* 字数 488 阅读 2083评论 ...

  3. struts标签怎么判断request里的属性是否为空 <s:if test="${list==null}"> </s:if>

    <s:if test="${weigou}==999"> //错误的 ${list==null} ,$实在strtus的配置文件中取值用的,不是在jsp页面里取值的的吧 ...

  4. 在kali linux上安装VMware tool

    在安全圈的门口徘徊了一年,一直不知道该如何入门,现在决定先从kali 入手.有同样兴趣的伙伴欢迎一起. 但是刚在VMware上安好系统就遇到了一个大麻烦,看了很多书,还有教程但总是遇到这样那样的问题. ...

  5. spring(AOP)静态代理

    姓名:黄于霞      班级:软件151 1.定义抽象主题接口,假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: 2.主题类,算术类,实现抽象接口. 3.代理类 4.测试运行 5.总 ...

  6. rebar3自动编译

    功能:修改完代码可以自动编译加载到VM中 必须安装的软件: Linux: inotify  链接https://github.com/rvoicilas/inotify-tools/wiki 配置: ...

  7. [BZOJ3167]Sao

    Problem 给你n个任务,n-1个关系,ab代表a在b前或者a在b后 问你有几种拓扑序 Solution f[i][j]表示第i个节点前有j个节点的方案数 设当前节点为x,儿子节点为s,若x依赖于 ...

  8. K2签约龙光地产,为集团实现“千亿目标”保驾护航

    随着房地产行业步入成熟期,行业整合及转型速度变快,房企要在数字经济的背景下实现稳步发展,企业信息化建设是其中的重要一环.此次龙光地产选择与K2携手,用统一流程平台为集团保驾护航,向实现千亿目标迈进. ...

  9. 用less编写百度搜索静态效果

    效果图 html页面 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  10. C# 事件的使用方法

    事件 事件是C#中另一高级概念,使用方法和委托相关.奥运会参加百米的田径运动员听到枪声,比赛立即进行.其中枪声是事件,而运动员比赛就是这个事件发生后的动作.不参加该项比赛的人对枪声没有反应. 从程序员 ...