React组件性高效渲染

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

组件更新特点:
(1)当一个组件的props或者state改变时,React通过比较新返回的元素和之前渲染的元素来决定是否有必要更新实际的DOM。当他们不相等时,React会更新DOM。(shouldComponentUpdate默认返回true)
(2)父组件更新默认触发所有子组件更新

性能优化


1.React组件渲染机制

这是官网给出的React组件渲染机制描述图。绿色的表示不需要更新。

component-update.png

通过观察我们发现:
影响更新的条件主要有SCU(shouldComponentUpdate)及DOM DIff结果。

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

render.png

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

  • shouldComponentUpdate 阶段判断,如果属性及状态与上一次相同,这个时候很明显UI不会变化,也不需要执行后续生成DOM,DOM Diff的过程了,可以提高性能。
  • DOM Diff 阶段优化,提高Diff的效率
2.如何提高组件的渲染效率
途径一:
  • 子组件执行 shouldComponentUpdate 方法,自行决定是否更新。具体来说就是当一些属性或状态相等时,我们不去更新。
(2.1)使用严格全等

我们可以通过控制子组件的 shouldComponentUpdate( 接收两个参数,分别为待更新的属性及状态值) 从而控制是否渲染:


way1.png

但是这里有两个问题

  • (1)当你的组件变得更加复杂时,你使用===比较属性和值以判定是否需要更新组件,但是书写会异常麻烦。
  • (2)当属性和状态里出现引用类型(数组,对象),此时直接通过===比较是行不通的,因为对象的引用类型。我们知道===对于引用类型的比较是通过比较地址来决定是否相等。除非你让它指向一个新的对象(即使值相等)或值,它才会更新。

我们先来看看第二问题


shadllowCompare.png

当我们点击按钮是,label里面并不会增加“sed”,也就是this.state.labelnextSate.label是一样的。我们查看控制台就可以知道:

console.png

然后我们把代码中的注释语句去掉,再把var arr=this.state.label; arr[3]="sed";注释掉。我们让arr指向一个全新的对象(值相同,值不相同更用说),再赋值给label,我们可以运行发现组件更新了。

这里我们就展示了使用===带来的副作用(虽然state:引用类型 已经改变,但组件不会更新),我们可以使用immutable.js来帮我们解决这个问题

(2.2)使用React.PureComponent

我们这里先来解决第一个问题,React提供了一个辅助对象来实现浅比较(shallowCompare)这种模式 - 继承自React.PureComponent。当组件更新时,如果组件的 props 和 state 都没发生改变,render 方法就不会触发,省去 Virtual DOM 的生成和比对过程,达到提升性能的目的。

way2.png

补充:React在之前版本提供了 PureRenderMixin 的mixin形式---react-addons-pure-render-mixin,也可以实现这样的功能。浅比较你可以简单看成===严格全等,但其实是===优化的结果,详情看你真的了解浅比较么?

PureComponent.png

当我们点击按钮是,label里面并不会增加“pattyzzh”,也就是我们上面的第二个问题依然存在。官网把这个问题归结为浅比较会忽略属性或状态突变的情况。其实以自己个人的理解就是引用带来的副作用。

这里的解决方案主要有:

  • 深比较: 对应深拷贝(完完全全复制一份)类似,比较耗时,不推荐。
  • immutable.js:FaceBook官方提出的不可变数据解决方案,主要解决了复杂数据在deepClone和对比过程中性能损耗
(2.3)immutable.js不可突变的数据结构

Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。

immutable.png

我们运行后会发现,正如上面提到对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象,所以shouldComponentUpdate中可以有效比较前后两次值是否相等。

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

参考
React组件性能调优
如何有效地提高react渲染效率--深复制,浅复制,immutable原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容

  • 说在前面 关于 react 的总结过去半年就一直碎碎念着要搞起来,各(wo)种(tai)原(lan)因(le)。心...
    陈嘻嘻啊阅读 6,796评论 7 41
  • 1. 前言 在 React 中,一切皆是组件,因此理解组件的工作流与核心尤为重要。我们有多种创建组件的方式(不仅 ...
    cbw100阅读 3,561评论 0 11
  • 3. JSX JSX是对JavaScript语言的一个扩展语法, 用于生产React“元素”,建议在描述UI的时候...
    pixels阅读 2,758评论 0 24
  • 原教程内容详见精益 React 学习指南,这只是我在学习过程中的一些阅读笔记,个人觉得该教程讲解深入浅出,比目前大...
    leonaxiong阅读 2,770评论 1 18
  • 听说生命是一条长长的河 传说河里只有鱼和水滴 水滴日夜不停 奔向远方 鱼儿终日无忧无虑在水中嬉戏玩耍 它们被称为这...
    追梦人hjw阅读 170评论 2 2