React/ReactNative優(yōu)化

React的特性


1. Learn once, write anywhere

學(xué)習(xí)React的好處就是,學(xué)了一遍之后妆偏,能夠?qū)憌eb, node直出我磁,以及native,能夠適應(yīng)各種紛繁復(fù)雜的業(yè)務(wù)厌衔。需要輕量快捷的璧帝,直接可以用Reactjs;需要提升首屏?xí)r間的富寿,可以結(jié)合React Server Render睬隶;需要更好的性能的,可以上React Native页徐。

但是苏潜,這其實(shí)暗示學(xué)習(xí)的曲線非常陡峭。單單是Webpack+ React + Redux就已夠一個(gè)入門(mén)者夠嗆变勇,更何況還要兼顧直出和手機(jī)客戶端恤左。不是一般人能hold住所有端。


2. Virtual Dom

Virtual Dom(下稱vd)算是React的一個(gè)重大的特色搀绣,因?yàn)镕acebook宣稱由于vd的幫助飞袋,React能夠達(dá)到很好的性能。是的链患,F(xiàn)acebook說(shuō)的沒(méi)錯(cuò)巧鸭,但只說(shuō)了一半,它說(shuō)漏的一半是:“除非你能正確的采用一系列優(yōu)化手段”麻捻。


3. 組件化

另一個(gè)被大家所推崇的React優(yōu)勢(shì)在于纲仍,它能令到你的代碼組織更清晰览闰,維護(hù)起來(lái)更容易。我們?cè)趯?xiě)的時(shí)候也有同感巷折,但那是直到我們踩了一些坑压鉴,并且漸漸熟悉React+ Redux所推崇的那套代碼組織規(guī)范之后。


上面的描述不免有些先揚(yáng)后抑的感覺(jué)锻拘,那是因?yàn)橥鳛镽eact的剛?cè)腴T(mén)者油吭,都會(huì)像我們初入的時(shí)候一樣,對(duì)React滿懷希望署拟,指意它幫我們做好一切婉宰,但隨著了解的深入,發(fā)現(xiàn)需要做一些額外的事情來(lái)達(dá)到我們的期待推穷。

對(duì)React的期待

初學(xué)者對(duì)React可能滿懷期待心包,覺(jué)得React可能完爆其它一切框架, 甚至不切實(shí)際地認(rèn)為React可能連原生的渲染都能完爆——對(duì)框架的 狂熱確實(shí)會(huì)出現(xiàn)這樣的不切實(shí)際的期待馒铃。讓我們來(lái)看看React的官方是怎么說(shuō)的蟹腾。React官方文檔在Advanced Performanec這一節(jié),這樣寫(xiě)道:

One of the first questions people ask when considering React for a project is whether their application will be as fast and responsive as an equivalent non-React version

顯然React自己也其實(shí)只是想盡量達(dá)到跟非React版本相若的性能区宇。React在減少重復(fù)渲染方面確實(shí)是有一套獨(dú)特的處理辦法娃殖,那就是vd (Virtual Dom),但顯示在首次渲染的時(shí)候React絕無(wú)可能超越原生的速度议谷,或者一定能將其它的框架比下去炉爆。因此,我們?cè)谧鰞?yōu)化的時(shí)候卧晓,可的期待的東西有:

  • 首屏?xí)r間可能會(huì)比原生的慢一些芬首,但可以嘗試用React Server Render (又稱Isomorphic)去提高效率
  • 用戶進(jìn)行交互的時(shí)候,有可能會(huì)比原生的響應(yīng)快一些逼裆,前提是你做了一些優(yōu)化避免了浪費(fèi)性能的重復(fù)渲染郁稍。

構(gòu)建針對(duì)React做的優(yōu)化


在PC端使用Redux的時(shí)候,我們都很喜歡使用Redux-Devtools來(lái)查看Redux觸發(fā)的action波附,以及對(duì)應(yīng)的數(shù)據(jù)變化艺晴。PC端使用的時(shí)候,我們習(xí)慣擺在右邊掸屡。但移動(dòng)端的屏幕較少封寞,因此家校群項(xiàng)目使用的時(shí)候放在底部,而且由于性能問(wèn)題仅财,我們?cè)赾onstant里設(shè)一個(gè)debug參數(shù)狈究,然后在chrome調(diào)試時(shí)打開(kāi),移動(dòng)端非必須的時(shí)候關(guān)閉盏求。否則抖锥,它會(huì)導(dǎo)致移動(dòng)web的渲染比較低下亿眠。

數(shù)據(jù)管理及性能優(yōu)化


Redux統(tǒng)一管理數(shù)據(jù)

這一部份算是重頭戲吧。React作為View層的框架磅废,已經(jīng)通過(guò)vd (Virtual Dom)幫助我們解決重復(fù)渲染的問(wèn)題纳像。但vd (Virtual Dom)是通過(guò)看數(shù)據(jù)的前后差異去判斷是否要重復(fù)渲染的,但React并沒(méi)有幫助我們?nèi)プ鲞@層比較拯勉。因此我們需要使用一整套數(shù)據(jù)管理工具及對(duì)應(yīng)的優(yōu)化方法去達(dá)成竟趾。在這方法,我們選擇了Redux宫峦。

Redux整個(gè)數(shù)據(jù)流大體可以用下圖來(lái)描述:

這里寫(xiě)圖片描述

Redux這個(gè)框架的好處在于能夠統(tǒng)一在自己定義的reducer函數(shù)里面去進(jìn)行數(shù)據(jù)處理岔帽,在View層中只需要通過(guò)事件去處觸發(fā)一些action就可以改變地應(yīng)的數(shù)據(jù),這樣能夠使數(shù)據(jù)處理和dom渲染更好地分離导绷,而避免手動(dòng)地去設(shè)置state犀勒。

在重構(gòu)的時(shí)候,我們傾向于將功能類似的數(shù)據(jù)歸類到一起妥曲,并建立對(duì)應(yīng)的reducer文件對(duì)數(shù)據(jù)進(jìn)行處理贾费。如下圖,是手Q家校群布置頁(yè)的數(shù)據(jù)結(jié)構(gòu)逾一。有些大型的SPA項(xiàng)目可能會(huì)將初始數(shù)據(jù)分開(kāi)在不同的reducer文件里铸本,但這里我們傾向于歸到一個(gè)store文件肮雨,這樣能夠清晰地知道整個(gè)文件的數(shù)據(jù)結(jié)構(gòu)遵堵,也符合Redux想統(tǒng)一管理數(shù)據(jù)的想法。然后數(shù)據(jù)的每個(gè)層級(jí)與reducer文件都是一一對(duì)應(yīng)的關(guān)系怨规。

這里寫(xiě)圖片描述

重復(fù)渲染導(dǎo)致卡頓

這套R(shí)eact + Redux的東西在PC家校群頁(yè)面上用得很歡樂(lè)陌宿, 以至于不用怎么寫(xiě)shouldComponentUpdate都沒(méi)遇到過(guò)什么性能問(wèn)題。但放到移動(dòng)端上波丰,我們?cè)诹斜眄?yè)重構(gòu)的時(shí)候就馬上遇到卡頓的問(wèn)題了壳坪。

什么原因呢?是重復(fù)渲染導(dǎo)致的j獭K!H移铩P恰!

說(shuō)好的React vd (Virtual Dom) 可以減少重復(fù)渲染呢先馆?7⒖颉!煤墙!

請(qǐng)別忘記前提條件C饭摺O苡怠!铣减!

你可以在每個(gè)component的render里她君,放一個(gè)console.log("xxx component")。然后觸發(fā)一個(gè)action葫哗,在優(yōu)化之前犁河,幾乎全部的component都打出這個(gè)log,表明都重復(fù)渲染了魄梯。

React性能的救星Immutablejs

這里寫(xiě)圖片描述
上圖是React的生命周期桨螺,還沒(méi)熟悉的同學(xué)可以去熟悉一下。因?yàn)槠渲械膕houldComponentUpdate是優(yōu)化的關(guān)鍵酿秸。React的重復(fù)渲染優(yōu)化的核心其實(shí)就是在shouldComponentUpdate里面做數(shù)據(jù)比較灭翔。在優(yōu)化之前,shouldComponentUpdate是默認(rèn)返回true的辣苏,這導(dǎo)致任何時(shí)候觸發(fā)任何的數(shù)據(jù)變化都會(huì)使component重新渲染肝箱。這必然會(huì)導(dǎo)致資源的浪費(fèi)和性能的低下——你可能會(huì)感覺(jué)比較原生的響應(yīng)更慢。

這時(shí)你開(kāi)始懷疑這世界——是不是Facebook在騙我稀蟋。

當(dāng)時(shí)遇到這個(gè)問(wèn)題我的開(kāi)始翻閱文檔煌张,也是在Facebook的Advanced Performance一節(jié)中找到答案:Immutablejs。這個(gè)框架已被吹了有一年多了吧退客,吹這些框架的人理解它的原理骏融,但不一定實(shí)踐過(guò)——因?yàn)樽鳛橐痪€移動(dòng)端開(kāi)發(fā)者,打開(kāi)它的github主頁(yè)看dist文件萌狂,50kb伦腐,我就已經(jīng)打退堂鼓了秆麸。只是遇到了性能問(wèn)題国旷,我們才再認(rèn)真地去了解一遍薇芝。

Immutable這個(gè)的意思就是不可變,Immutablejs就是一個(gè)生成數(shù)據(jù)不可變的框架务傲。一開(kāi)始你并不理解不可變有什么用凉当。最開(kāi)始的時(shí)候Immutable這種數(shù)據(jù)結(jié)構(gòu)是為了解決數(shù)據(jù)鎖的問(wèn)題,而對(duì)于js售葡,就可以借用來(lái)解決前后數(shù)據(jù)比較的問(wèn)題——因?yàn)橥瑫r(shí)Immutablejs還提供了很好的數(shù)據(jù)比較方法——Immutable.is()看杭。小結(jié)一下就是:

  • Immutablejs本身就能生成不可變數(shù)據(jù),這樣就不需要開(kāi)發(fā)者自己去做數(shù)據(jù)深拷貝天通,可以直接拿prevProps/prevState和nextProps/nextState來(lái)比較泊窘。
  • Immutable本身還提供了數(shù)據(jù)的比較方法,這樣開(kāi)發(fā)者也不用自己去寫(xiě)數(shù)據(jù)深比較的方法。

說(shuō)到這里烘豹,已萬(wàn)事俱備了瓜贾。那東風(fēng)呢?我們還欠的東風(fēng)就是應(yīng)該在哪里寫(xiě)這個(gè)比較携悯。答案就是shouldComponentUpdate祭芦。這個(gè)生命周期會(huì)傳入nextProps和nextState,可以跟component當(dāng)前的props和state直接比較憔鬼。這個(gè)就可以參考pure-render的做法龟劲,去重寫(xiě)shouldComponentUpdate,在里面寫(xiě)數(shù)據(jù)比較的邏輯轴或。

那具體怎么使用immutable + pure-render呢昌跌?

對(duì)于immutable,我們需要改寫(xiě)一下reducer functions里面的處理邏輯照雁,一律換成Immutable的api蚕愤。

至于pure-render,若是es5寫(xiě)法饺蚊,可以用使mixin萍诱;若是es6/es7寫(xiě)法,需要使用decorator污呼,在js的babel loader里面裕坊,新增plugins: [‘transform-decorators-legacy’]。其es6的寫(xiě)法是

@pureRender
export default class List extends Component { ... }

Immutablejs帶來(lái)的一些問(wèn)題

不重新渲染

你可能會(huì)想到Immutable能減少無(wú)謂的重新渲染燕酷,但可能沒(méi)想過(guò)會(huì)導(dǎo)致頁(yè)面不能正確地重新渲染籍凝。
引入immutable和pureRender后,render里的JSX注意一定不要有同樣的key(如兩個(gè)列表悟狱,有重復(fù)的數(shù)據(jù)静浴,此時(shí)以數(shù)據(jù)id來(lái)作為key就不太合適,應(yīng)該要用數(shù)據(jù)id + 列表類型作為key)挤渐,會(huì)造成不渲染新數(shù)據(jù)情況。

Immutablejs太大了

上文也提到Immutablejs編譯后的包也有50kb双絮。對(duì)于PC端來(lái)說(shuō)可能無(wú)所謂浴麻,網(wǎng)速足夠快,但對(duì)于移動(dòng)端來(lái)說(shuō)壓力就大了囤攀。有人寫(xiě)了個(gè)seamless-immutable软免,算是簡(jiǎn)易版的Immutablejs,只有2kb焚挠,只支持Object和Array膏萧。


性能優(yōu)化Tips

這里歸納了一些其它性能優(yōu)化的小Tips

請(qǐng)慎用setState,因其容易導(dǎo)致重新渲染

既然將數(shù)據(jù)主要交給了Redux來(lái)管理,那就盡量使用Redux管理你的數(shù)據(jù)和狀態(tài)state榛泛,除了少數(shù)情況外蝌蹂,別忘了shouldComponentUpdate也需要比較state。

請(qǐng)將方法的bind一律置于constructor

Component的render里不動(dòng)態(tài)bind方法曹锨,方法都在constructor里bind好孤个,如果要?jiǎng)討B(tài)傳參,方法可使用閉包返回一個(gè)最終可執(zhí)行函數(shù)沛简。如:showDelBtn(item) { return (e) => {}; }齐鲤。如果每次都在render里面的jsx去bind這個(gè)方法,每次都要綁定會(huì)消耗性能椒楣。

請(qǐng)只傳遞component需要的props

傳得太多给郊,或者層次傳得太深,都會(huì)加重shouldComponentUpdate里面的數(shù)據(jù)比較負(fù)擔(dān)捧灰,因此丑罪,也請(qǐng)慎用spread attributes(<Component {...props} />)。

請(qǐng)盡量使用const element

我們將不怎么變動(dòng)凤壁,或者不需要傳入狀態(tài)的component寫(xiě)成const element的形式吩屹,這樣能加快這個(gè)element的初始渲染速度。

路由控制與拆包

當(dāng)項(xiàng)目變得更大規(guī)模與復(fù)雜的時(shí)候拧抖,我們需要設(shè)計(jì)成SPA煤搜,這時(shí)路由管理就非常重要了,這使特定url參數(shù)能夠?qū)?yīng)一個(gè)頁(yè)面唧席。
這里寫(xiě)圖片描述

React性能優(yōu)化軍規(guī)

渲染相關(guān)

  • 提升級(jí)項(xiàng)目性能擦盾,請(qǐng)使用immutable(props、state淌哟、store)
  • 請(qǐng)pure-render-decorator與immutablejs搭配使用
  • 請(qǐng)慎用setState迹卢,因其容易導(dǎo)致重新渲染
  • 謹(jǐn)慎將component當(dāng)作props傳入
  • 請(qǐng)將方法的bind一律置于constructor
  • 請(qǐng)只傳遞component需要的props,避免其它props變化導(dǎo)致重新渲染(慎用{...this.props}
  • 請(qǐng)?jiān)谀阆Ml(fā)生重新渲染的dom上設(shè)置可被react識(shí)別的同級(jí)唯一key徒仓,否則react在某些情況可能不會(huì)重新渲染腐碱。
  • 請(qǐng)盡量使用const element

Debug相關(guān)

  • 移動(dòng)端請(qǐng)慎用redux-devtools,易造成卡頓
  • Webpack慎用devtools的inline-source-map模式
    使用此模式會(huì)內(nèi)聯(lián)一大段便于定位bug的字符串掉弛,查錯(cuò)時(shí)可以開(kāi)啟症见,不是查錯(cuò)時(shí)建議關(guān)閉,否則開(kāi)發(fā)時(shí)加載的包會(huì)非常大殃饿。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谋作,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乎芳,更是在濱河造成了極大的恐慌遵蚜,老刑警劉巖帖池,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異吭净,居然都是意外死亡睡汹,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)攒钳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)帮孔,“玉大人,你說(shuō)我怎么就攤上這事不撑∥木ぃ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵焕檬,是天一觀的道長(zhǎng)姆坚。 經(jīng)常有香客問(wèn)我,道長(zhǎng)实愚,這世上最難降的妖魔是什么兼呵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮腊敲,結(jié)果婚禮上击喂,老公的妹妹穿的比我還像新娘。我一直安慰自己碰辅,他們只是感情好懂昂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著没宾,像睡著了一般凌彬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上循衰,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天铲敛,我揣著相機(jī)與錄音,去河邊找鬼会钝。 笑死伐蒋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的顽素。 我是一名探鬼主播咽弦,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼胁出!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起段审,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤全蝶,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體抑淫,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绷落,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了始苇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砌烁。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖催式,靈堂內(nèi)的尸體忽然破棺而出函喉,到底是詐尸還是另有隱情,我是刑警寧澤荣月,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布管呵,位于F島的核電站,受9級(jí)特大地震影響哺窄,放射性物質(zhì)發(fā)生泄漏捐下。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一萌业、第九天 我趴在偏房一處隱蔽的房頂上張望坷襟。 院中可真熱鬧,春花似錦生年、人聲如沸婴程。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)排抬。三九已至,卻和暖如春授段,著一層夾襖步出監(jiān)牢的瞬間蹲蒲,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工侵贵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留届搁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓窍育,卻偏偏與公主長(zhǎng)得像卡睦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漱抓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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