React Native 組件性能優(yōu)化

前言

影響性能最大的因素是界面的重繪和重排版,React 背后的 Virtual DOM 就是盡可能地減少重繪與重排版荚藻。
我們需要提高 React Virtual DOM 的效率,從 React 渲染過程看崖蜜,如何防止不必要的渲染可能是最需要取解決的問題凄贩。針對這個問題,React 官方提供了一個便捷的方法來解決巾腕,那就是 PureRender。

純函數(shù)

要理解 PureRender 中的 Pure絮蒿,要從函數(shù)式編程的的基本概念 "純函數(shù)"講起尊搬。純函數(shù)由三大原則構(gòu)成。

  • 給定相同的輸入土涝,他總是返回相同的輸出

對于一個方法佛寿,只要我們傳入的值是固定,無論做多少次調(diào)用回铛,結(jié)果都是一樣狗准。有些方法不依賴于你傳入的參數(shù),如 Math.random()茵肃,不傳任何參數(shù)到方法中腔长,該方法依然總是會輸出不同的結(jié)果,這種方法也是純函數(shù)验残。還有常用的 slice 和 splice 方法捞附,slice在參數(shù)一致的時候結(jié)果都是一致的,splice方法的執(zhí)行結(jié)果會改變原來數(shù)組您没,對于程序來說鸟召,splice 的隱藏行為是危險的,所以 splice 不是純函數(shù)氨鹏。

  • 過程沒有副作用

在純函數(shù)中我們不能改變外部狀態(tài)欧募。

  • 沒有額外的狀態(tài)依賴

方法內(nèi)的狀態(tài)都只在方法的生命周期內(nèi)存活,意味著不能在方法內(nèi)使用共享變量仆抵,這會給方法帶來不可知因素跟继。

純函數(shù)也是函數(shù)式編程的基礎(chǔ),他完全獨立于外部狀態(tài)镣丑,這樣就避免了因為共享外部狀態(tài)而導(dǎo)致的 bug舔糖。
純函數(shù)非常方便方法級別的測試以及重構(gòu),可以讓程序具有良好的擴展性及適應(yīng)性莺匠。
React 就是函數(shù)式編程金吗,React 組件本身就是純函數(shù),可以表示為 UI = f(data),data 包括 props 和 state摇庙,改變 data旱物,就能改變 UI,而不是像 JQuery 一樣直接操縱 UI跟匆。
可以通過拆分組件為自組件异袄,進(jìn)而對組件做更小顆粒度的控制。這是函數(shù)式編程的魅力之一玛臂,保持純凈狀態(tài),讓方法或組件更加專注 (focused)封孙,體積更小 (small)迹冤,更獨立(independent),更具有復(fù)用性 (reustability)虎忌。

PureRender

pureRender 指的就是組件滿足純函數(shù)條件泡徙,即組件的渲染是被相同的 props 和 state 渲染進(jìn)而得到相同的結(jié)果。

1. PureRender 的本質(zhì)

React 生命周期中有一個 shouldComponentUpdate 方法膜蠢,如果返回 true堪藐,表示需要渲染,返回 false 表示不需要渲染挑围。

2. 運用 PureRender

React 新版本提供一個 PureComponent礁竞,PureComponent 內(nèi)部重新實現(xiàn) shouldComponentUpdate 方法,讓當(dāng)前傳入的 props 和 state 與之前的作淺比較,杉辙,淺比較對 object 只作了引用比較模捂,并沒有做值比較,如果返回 false蜘矢,那么組件就不會執(zhí)行 render 方法狂男。

3. 優(yōu)化 PureRender

  • 直接為props設(shè)置對象或數(shù)組

每次調(diào)用 React 組件其實都會重新創(chuàng)建組件,就算傳入的數(shù)組或?qū)ο蟮闹禌]有改變品腹,它們引用的地址也會發(fā)生改變岖食。

<TestComponent 
    style={{background: 'white'}}
/>

我們可以把傳入的數(shù)組或?qū)ο蟊4娉梢环菀谩?/p>

<TestComponent 
    style={styles.container}
/>
const styles = StyleSheet.create({
    container: {
        background: 'white'
    },
});
  • 設(shè)置 props 方法并通過事件綁定在元素上
onPress() {
}
<TestComponent 
    onPress={this.onPress.bind(this)}
/>

這樣寫,每一次渲染都會重新綁定 onPress方法, 不要讓方法每一次都綁定舞吭,因此把綁定移動到構(gòu)造器內(nèi)泡垃。

constructor(props) {
    super(props);
    this.onPress = this.onPress.bind(this);
}

onPress() {
}

render() {
    <TestComponent 
        onPress={this.onPress}
    />
}

Immutable

在傳遞的數(shù)據(jù)的時候,可以直接使用 Immutable Data 來進(jìn)一步提高組件的渲染性能镣典。

1. Immutable Data

Immutable Data 就是一旦創(chuàng)建兔毙,就不能再更改的數(shù)據(jù)。對 Immutable 對象進(jìn)行修改兄春,添加或者刪除操作澎剥,都會返回一個新的 Immutable 對象。Immutable 實現(xiàn)的原理是持久化的數(shù)據(jù)結(jié)構(gòu),也就是使用舊數(shù)據(jù)創(chuàng)建新數(shù)據(jù)哑姚,要保證就數(shù)據(jù)同時可用切不變祭饭。同時為了避免深拷貝把所有節(jié)點都復(fù)制一遍帶來的性能損耗,Immtable 使用了結(jié)構(gòu)共享叙量,即如果對象樹中一個節(jié)點發(fā)生變化倡蝙,只修改這個節(jié)點和受他影響的父節(jié)點,其他節(jié)點進(jìn)行共享绞佩。

  • Map:鍵值對集合寺鸥,對應(yīng)于Object。
  • List:有序可重復(fù)的列表品山,對應(yīng)于Array胆建。
  • ArraySet:無序切不可重復(fù)的列表。

2. Immutable 的優(yōu)點

  • 降低了 "可變" 帶來的復(fù)雜度肘交。
  • 節(jié)省內(nèi)存笆载。Immutable 使用結(jié)構(gòu)共享盡量復(fù)用內(nèi)存。沒有被引用的對象會被垃圾回收涯呻。
  • 撤銷/重做凉驻,復(fù)制/粘帖,甚至?xí)r間旅行這些功能做起來都變得簡單复罐。因為每次數(shù)據(jù)都是不一樣的涝登,那么只要把這些數(shù)據(jù)都放到一個數(shù)組里存儲起來,想回退到哪里市栗,就拿出對應(yīng)的數(shù)據(jù)缀拭。
  • 并發(fā)安全。Immutable 數(shù)據(jù)天生不可變填帽,但 js 是單線程運行蛛淋,現(xiàn)在并沒有什么用。
  • 擁抱函數(shù)式編程篡腌。只要輸入一致褐荷,那么輸出必然一致,這樣開發(fā)的組件更易于調(diào)試和組裝嘹悼。

3. 使用 Immutable 的缺點

容易與原生對象混淆叛甫。

4. Immutable.is

為了直接比較對象的值,Immutable提供了Immutable.is 來作"值比較"

const map1 = Immutable.Map({a: 1, b: 1})
const map2 = Immutable.Map({a: 1, b: 1})
map1 === map2; // => false
Immutable.is(map1, map2); // => true

Immutable.is比較的是兩個對象的hashCode 或 valueOf (對于JS 對象)杨伙,由于Immutable 內(nèi)部使用 trie 數(shù)據(jù)結(jié)構(gòu)來存儲其监,只要兩個對象 hashCode 相等,值就是一樣的限匣。

5. Immutable 和 PureRender

React 做性能優(yōu)化最常用的就是 shouldComponentUpdate 方法抖苦,但他默認(rèn)返回true,即始終會執(zhí)行 render 方法,然后做 Virtual DOM比較锌历,并得出是否需要做真實 DOM 更新贮庞,這里往往帶來不必要的渲染,
當(dāng)然究西,我們可以在 shouldComponentUpdate 中使用深拷貝和深比較來避免無必要的 render窗慎,但是深拷貝和深比較一般都是非常昂貴的選擇。
Immutable.js 提供了簡潔卤材,高效的判斷數(shù)據(jù)是否變化的方法遮斥,只需要 is 比較就能知道是否需要執(zhí)行 render,而這個操作幾乎零成本商膊,所以可以極大提高性能伏伐。修改后的 shouldComponentUpdate 是這樣的。

import React, {
    Component
} from 'react';
import Immutable from 'immutable';

class BaseComponent extends Component {

    shouldComponentUpdate(nextProps, nextState = {}) {
        return !Immutable.is(Immutable.fromJS(this.props), Immutable.fromJS(nextProps))
        || !Immutable.is(Immutable.fromJS(this.state), Immutable.fromJS(nextState));
    }
}

export default BaseComponent;

而在自定義組件你只需要繼承BaseComponent晕拆,就可以攔截不必要的渲染。

class App extends BaseComponent {

}

6. key

寫動態(tài)組件的時候材蹬,需要給動態(tài)子組件添加 key props实幕,否則會報一個警告。Key 要保持惟一堤器,穩(wěn)定昆庇。
key 的作用是為了 Virtual DOM 在執(zhí)行 diff 算法時更快地找到對應(yīng)的節(jié)點,提高 diff 速度闸溃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末整吆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子辉川,更是在濱河造成了極大的恐慌表蝙,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乓旗,死亡現(xiàn)場離奇詭異府蛇,居然都是意外死亡,警方通過查閱死者的電腦和手機屿愚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門汇跨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妆距,你說我怎么就攤上這事穷遂。” “怎么了娱据?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵蚪黑,是天一觀的道長。 經(jīng)常有香客問我,道長祠锣,這世上最難降的妖魔是什么酷窥? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮伴网,結(jié)果婚禮上蓬推,老公的妹妹穿的比我還像新娘。我一直安慰自己澡腾,他們只是感情好沸伏,可當(dāng)我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著动分,像睡著了一般毅糟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上澜公,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天姆另,我揣著相機與錄音,去河邊找鬼坟乾。 笑死迹辐,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的甚侣。 我是一名探鬼主播明吩,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼殷费!你這毒婦竟也來了印荔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤详羡,失蹤者是張志新(化名)和其女友劉穎仍律,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體殷绍,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡染苛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了主到。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茶行。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖登钥,靈堂內(nèi)的尸體忽然破棺而出畔师,到底是詐尸還是另有隱情,我是刑警寧澤牧牢,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布看锉,位于F島的核電站姿锭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏伯铣。R本人自食惡果不足惜呻此,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腔寡。 院中可真熱鬧焚鲜,春花似錦、人聲如沸放前。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凭语。三九已至葱她,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間似扔,已是汗流浹背吨些。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炒辉,地道東北人锤灿。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像辆脸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子螃诅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,543評論 2 349

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