【React】—組件性能優(yōu)化

一憔恳、優(yōu)化原理

改寫react生命周期shouldComponentUpdate烁挟,使其在需要重新渲染當(dāng)前組件時(shí)返回true,否則返回false兜看。不再全部返回true锥咸。

二、主流優(yōu)化方式

1.react官方解決方案

原理:重寫默認(rèn)的shouldComponentUpdate细移,將舊props搏予、state與新props、state逐個(gè)進(jìn)行淺比較(形如:this.props.option === nextProps.option ?? false : true)弧轧,如果全部相同雪侥,返回false,如果有不同精绎,返回true速缨。

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>
????}

}

es7裝飾器的寫法:

import pureRender from "pure-render-decorator"

...

@pureRender

class SampleComponent extends Component {

????render() {

????????return (

? ? ????????<div className={this.props.className}>foo</div>

????????)

????}

}

react 15.3.0+寫法(用來替換react-addons-pure-render-mixin):

class?SampleComponent extends React.PureComponent{

? ? render(){

? ? ? ? return(

? ? ? ? ? ? <div className={this.props.className}>foo</div>

????????)

????}

}

*上述方案存在問題(淺比較的問題):

(1)某些props、state值未改變的情況代乃,返回true旬牲,例如:

?<Cell options={this.props.options || [ ]} />

當(dāng)this.props.options == false時(shí),options=[ ]。當(dāng)父組件兩次渲染原茅,this.props.options一直 == false牍陌,對(duì)于Cell組件來說,options沒有改變员咽,不需要重新渲染毒涧。但Cell的shouldComponentUpdate中進(jìn)行的是淺比較,由于[ ] !== [ ]贝室,所以契讲,this.props.options === nextProps.options為false,shouldComponentUpdate會(huì)返回true滑频,Cell將進(jìn)行重新渲染捡偏。

解決方法如下:

const default = [ ];

<Cell options={this.props.options || default} />

(2)某些props、state值改變的情況峡迷,返回false银伟,例如:

handleClick() {

????let {items} = this.state;

????items.push('new-item') ;

????this.setState({ items });

}

render() {

????return (

????????<div>

????????????<button onClick={this.handleClick} />

????????????<ItemList items={this.state.items} />

????????</div>
????)

}

如果ItemList是純組件(PureComponent),那么這時(shí)它是不會(huì)被渲染的绘搞。因?yàn)楸M管this.state.items的值發(fā)生了改變彤避,但是它仍然指向同一個(gè)對(duì)象的引用。




2.Immutable

原理:Persistent Data Structure(持久化數(shù)據(jù)結(jié)構(gòu))夯辖,也就是使用舊數(shù)據(jù)創(chuàng)建新數(shù)據(jù)時(shí)琉预,要保證舊數(shù)據(jù)同時(shí)可用且不變。

Immutable Data就是一旦被創(chuàng)建蒿褂,就不能再更改的數(shù)據(jù)圆米。對(duì) Immutable 對(duì)象的任何修改或添加刪除操作都會(huì)返回一個(gè)新的 Immutable 對(duì)象。同時(shí)啄栓,為了避免 deepCopy 把所有節(jié)點(diǎn)都復(fù)制一遍帶來的性能損耗娄帖,Immutable 使用了?Structural Sharing(結(jié)構(gòu)共享),即如果對(duì)象樹中一個(gè)節(jié)點(diǎn)發(fā)生變化昙楚,只修改這個(gè)節(jié)點(diǎn)和受它影響的父節(jié)點(diǎn)近速,其它節(jié)點(diǎn)則進(jìn)行共享。

【在react中使用immutable】

改變shouldComponentUpdate的重新渲染規(guī)則

(1)防止每次setState或傳遞props桂肌,即使state和props的值沒有發(fā)生改變也重新渲染組件数焊,帶來無謂的性能消耗

(2)防止淺比較帶來的比較誤差問題,以及深比較帶來的性能消耗問題崎场。

import { is, fromJS } from 'immutable';

constructor(){

? ??this.state = {

????????person: fromJS({

????????????????name: 'xuxuan',

????????????????age: 12?

????????});

? ?}

}

componentDidMount(){

????this.setState({

????????person: this.state.person.update('name', v => v + 'update')

????});

}

shouldComponentUpdate: (nextProps, nextState) => {

????return !(this.props === nextProps || is(this.props, nextProps))

????????????????||

? ? ? ? ????? !(this.state === nextState || is(this.state, nextState));

}

!!注意】state 本身必須是普通對(duì)象佩耳,但是里面的值可以是 immutable 的數(shù)據(jù)。

this.state和nextState是兩個(gè)普通對(duì)象谭跨,通過is方法判斷二者的值是否相同干厚。


從setState到re-render整個(gè)過程(個(gè)人理解)

(1)setState中設(shè)置person的name值李滴,由于person是immutable的,因此蛮瞄,這里會(huì)開辟一塊新的內(nèi)存所坯,存儲(chǔ)設(shè)置后的name(即使name的值沒有真的發(fā)生改變,只要對(duì)immutable數(shù)據(jù)進(jìn)行了設(shè)置操作挂捅,就會(huì)生成一個(gè)全新的對(duì)象)芹助,同時(shí),開辟新內(nèi)存闲先,存儲(chǔ)受name影響的immutable的各級(jí)父節(jié)點(diǎn)状土,這里只有person。而伺糠,其余未受影響的節(jié)點(diǎn)蒙谓,將進(jìn)行內(nèi)存共享,如這里的age训桶。由此累驮,形成了新的state對(duì)象,即:nextState舵揭。

(2)setState(nextState)操作觸發(fā)shouldComponentUpdate生命周期執(zhí)行谤专。

(3)shouldComponentUpdate中使用immutable.js的is方法對(duì)比兩個(gè)對(duì)象。

????????這里琉朽,is采用hashCodevalueOf對(duì)比兩個(gè)對(duì)象是否相同:

? ? ? ? *當(dāng)對(duì)象的值沒有改變毒租,is返回true,組件不重新渲染箱叁。依然存儲(chǔ)舊的state(nextState大概會(huì)被銷毀吧)

? ? ? ? *當(dāng)對(duì)象的值發(fā)生改變,is返回false,組件重新渲染。nextState替換state(state就不能再訪問了庸疾,但它的immutable的屬性應(yīng)該還可以)

(4)當(dāng)需要重新渲染的時(shí)候肋杖,對(duì)于state來說,就是用新的nextState替換舊的state桥胞。由于state是普通對(duì)象,因此可以被更改,被替換妓笙。


【關(guān)于is方法】

Immutable的is比較的是這個(gè)對(duì)象hashCodevalueOf,只要兩個(gè)對(duì)象的hashCode相等能岩,值就是相同的寞宫,避免了深度遍歷,提高了性能拉鹃。

擴(kuò)展:

hashCode的比較是將兩個(gè)對(duì)象String化(eg:{a:111} —> '{a:111}')后辈赋,比較兩個(gè)字符串對(duì)應(yīng)位置字符的charCode是否相同鲫忍,完全相同則認(rèn)為是兩個(gè)相同的對(duì)象。


使用?Immutable?后钥屈,如下圖悟民,當(dāng)紅色節(jié)點(diǎn)的?state 屬性值變化后,


Immutable數(shù)據(jù)樹結(jié)構(gòu)變化示意圖

【注】

整棵樹就是一個(gè)Immutable的對(duì)象篷就。

當(dāng)紅色節(jié)點(diǎn)發(fā)生改變射亏,為這個(gè)節(jié)點(diǎn)及其父節(jié)點(diǎn)開辟新的內(nèi)存,存儲(chǔ)新數(shù)據(jù)竭业,其他藍(lán)色節(jié)點(diǎn)不變鸦泳,共享之前的內(nèi)存。


immutable.js框架是非常好的Immutable庫(kù)永品,其他可用api做鹰,詳見官方文檔。

使用原則:

由于侵入性較強(qiáng)鼎姐,新項(xiàng)目引入比較容易钾麸,老項(xiàng)目遷移需要謹(jǐn)慎評(píng)估遷移成本。對(duì)于一些提供給外部使用的公共組件炕桨,最好不要把Immutable對(duì)象直接暴露在對(duì)外的接口中饭尝。


【!!Mark】

個(gè)人理解部分,如有理解偏差献宫,請(qǐng)指正钥平,感謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姊途,一起剝皮案震驚了整個(gè)濱河市涉瘾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捷兰,老刑警劉巖立叛,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異贡茅,居然都是意外死亡秘蛇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門顶考,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赁还,“玉大人,你說我怎么就攤上這事驹沿∷也撸” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵甚负,是天一觀的道長(zhǎng)柬焕。 經(jīng)常有香客問我审残,道長(zhǎng),這世上最難降的妖魔是什么斑举? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任搅轿,我火速辦了婚禮,結(jié)果婚禮上富玷,老公的妹妹穿的比我還像新娘璧坟。我一直安慰自己,他們只是感情好赎懦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布雀鹃。 她就那樣靜靜地躺著,像睡著了一般励两。 火紅的嫁衣襯著肌膚如雪黎茎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天当悔,我揣著相機(jī)與錄音傅瞻,去河邊找鬼。 笑死盲憎,一個(gè)胖子當(dāng)著我的面吹牛嗅骄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饼疙,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼溺森,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了窑眯?” 一聲冷哼從身側(cè)響起屏积,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伸但,沒想到半個(gè)月后肾请,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡更胖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了隔显。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片却妨。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖括眠,靈堂內(nèi)的尸體忽然破棺而出彪标,到底是詐尸還是另有隱情,我是刑警寧澤掷豺,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布捞烟,位于F島的核電站薄声,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏题画。R本人自食惡果不足惜默辨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望苍息。 院中可真熱鬧缩幸,春花似錦、人聲如沸竞思。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)盖喷。三九已至爆办,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間课梳,已是汗流浹背距辆。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惦界,地道東北人挑格。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像沾歪,于是被迫代替她去往敵國(guó)和親漂彤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容