React渲染問題研究以及Immutable的應用
渲染房間列表
這個例子主要是寫了同時渲染1000個房間,如果我添加一個房間或者修改一個房間,在react中不同的實現方式下render函數將會表現出什麼樣的結果?以及針對不同結果的一些思考和優化。大致的列表例子如下:生成1000個不同的房間盒子,顏色隨機。
項目整體目錄結構大致是這樣的:
下面主要來看ListDetail.js中是如何寫的:
父組件List
子組件RoomDetail,
子組件的功能只是純粹的渲染功能,自身並沒有任何操作
子組件:
父組件:
下面我們來添加一個房間試試
這個操作主要是生成一個新的房間,然後從state中取出當前的房間列表,然後再當前的房間列表中添加一個新的房間,最後將整個列表從新設置到狀態中。
很顯然,此時由於父組件的狀態發生了變化,會引起自身的render函數執行,同時列表開始重新遍歷,然後將每一個房間信息重新傳入到子組件中。是的,重新傳入,就代表了子組件將會重新渲染。我們可以來做一個測試,在子組件的render
方法中加入如下列印:
不出意外的發現了所有的子組件渲染的證據:
同時利用chorme的Performance檢測的信息如下:
調用的方法堆棧如下:
渲染子組件的時間達到764ms,同時在堆棧中可以看到大量的receiveComponent和updateChildren方法的執行。那麼有沒有什麼辦法只渲染改變的部分呢?在react官網性能監控這一小節中有提到一個方法,將子組件繼承React.PureComponent可以局部有效防止渲染。加上之後的代碼是這樣的:
所有的東西都沒有變化,只是將Component換成了PureComponent。下面我們再來測試一下:
性能檢測圖如下:
效果出奇的好,果然只是渲染了一次,並且速度提升了10幾倍之多。其中的原理是在組件的shouldComponentUpdate方法中進行了props與state的比較,如果認為他們相等,則會返回false,否則則會返回true。
同時官網也說了,這只是局部有效,為什麼呢?因為這些值的比較都只是淺比較,也就是只是第一層的比較。那麼會出現什麼問題,我們來看下面的操作:
修改其中的一個房間:
很意外,當我添加了一個房間之後,發現第一個房間並沒有我們想像中的發生變化。為什麼?
原因是我雖然修改了第一個房間的數據,當時我並沒有修改他的引用地址。類似下面這樣的:
因此在子組件中比較房間的時候,就會出現比較的值相等的情況,此時將會返回false那麼有沒有辦法改變這個問題,我找到了兩個辦法:
從數據源頭入手
從子組件是否渲染條件入手
從數據源頭入手,即為改造數據,將數據進行深拷貝,使得原先的引用與新得到的對象的引用不相同即可。關於深拷貝的實現方法有很多,我這裡貼一個,之後再仔細做研究。
在ES6中提供了一種解構方式,這種方式也可以實現數組的深層次拷貝。類似這樣的
因此我把modifyRoom函數進行了如此改造:
因此在比較第一個對象的時候,發現它們已經不相等了,則會重新渲染。
從子組件是否渲染條件入手,可以不需要使用React.PureComponent,而直接在shouldComponentUpdate方法入手。因為兩次值改變之後,我清楚得可以知道,改變的值只是第一個對象中的數值改變。那麼我可以這麼寫來判斷:
同樣得可以達到效果。但是如果在shouldComponentUpdate中存在著多個props和state中值改變的話,就會使得比較變得十分複雜。應用Immutable.js來檢測React中值的變化問題在官網上來說,immutable提供的數據具有不變性,被稱作為Persistent data structure,又或者是functional data structure,非常適用於函數式編程,相同的輸入總會預期到相同的輸出。
2.1 immutable的性能在immutable官網以及在知乎中談到為什麼要使用immutable的時候,會看到一個關鍵詞efficient。高效地,在知乎上看到說是性能十分好。在對象深複製、深比較上對比與Javascript的普通的深複製與比較上來說更加地節省空間、提升效率。我在這裡做出一個實驗(這裡我並不保證實驗的準確性,只是為了驗證一下這個說法而已)。
實驗方法:我這裡會生成一個對象,對象有一個廣度與深度,廣度代表第一層對象中有多少個鍵值,深度代表每一個鍵值對應的值會有多少層。類似這樣的:
因此實際上在javascript對象的複製和比較上,需要遍歷的次數其實是width * deep。
在複製的問題上,我做了三種比較。
deepCopy(obj)
JSON.parse(JSON.stringify(obj))
Immutable
最終得到的數據為:
deepCopy( μs ) | JSON( μs ) | Immutable( μs ) | |
---|---|---|---|
20 * 50 | 4000 | 9000 | 20 |
20 * 500 | 8000 | 10000 | 20 |
20 * 5000 | 10000 | 14000 | 20 |
在比較上,我只比較了兩種方式:
javascript deep compare
Immutable.is
代碼如下:
最終得到的數據為:
deepCompare( μs ) | Immutable.is( μs ) | |
---|---|---|
20 * 5 | 0 | 7000 |
20 * 50 | 1000 | 27000 |
20 * 500 | 6000 | 24000 |
20 * 5000 | 84000 | 5000 |
數據的設計上可能太過單一,沒有涉及到複雜的數據,比如說對象中再次嵌套數組,並且在每一個鍵值對應的值得廣度上設計得也太過單一,只是一條直線下來。但是當數據量達到一定的程度時,其實也說明了一些問題。
總結:
對象複製上來說,基本上Immutable
可以說是零消耗Immutable
並快不了多少Immutable.is()
所用的時間會更少
對象比較上,當對象深層嵌套到一定規模,反而
但是在數據方面來說,
當然只是測試,平時中的縱向嵌套達到三層以上都會認為是比較恐怖的了。
於是我去網上翻了翻,看看有沒有什麼更好的demo,下面我摘錄一些話。
What is the benefit of immutable.js?
Immutable.js makes sure that the"state" is not mutated outsideof say redux. For smaller projects, personally i don"t think it is worth it but for bigger projects with more developers, using the same set of API to create new state in reduce is quite a good idea
It was mentioned many times before that Immutable.jshas some internal optimizations, such as storing lists as more complex tree structures which give better performance when searching for elements. It"s also often pointed out that using Immutable.js enforces immutability, whereas using Object.assign or object spread and destructuring assignments relies to developers to take care of immutability. EDIT:I haven"t yet seen a good benchmark of Immutable.js vs no-library immutability.If someone knows of one please share. Sharing is caring
Immutable.js addstwothings:Code enforcement:by disallowing mutations, you avoid strange errors in redux and react. Code is substantially easier to reason about.Performance: Mutation operations for larger objects are substantially faster as the internals are a tree structure that does not have to copy the entirety of an object every assignment.In conclusion: it"s a no brainer for decently scoped applications; but for playing around it"s not necessary.
yes, obviouslymutable is the fastestbut it won"t work with how redux expects the data, which is immutable
Performance Tweaking in React.js using Immutable.js
But wait… This is can get really ugly really fast. I can think of two general cases where your
// Too many props and state to check!
shouldComponentUpdate
can get out of hand.
是的,我並沒有得出Immutable在性能上一定會很快的真實數據。但是不得不提到的是他在配合Redux使用的時候的一個天然優勢——數據是不變的。並且在最後一個鏈接中也提到,在配合React使用中通過控制shouldComponentUpdate來達到優化項目的目的。
however,Let"s write some examples about immutable used in react to make sense.
2.2 房間列表加入Immutable
在父組件中的改變:
子組件中:
將數據源用Immutable初始化之後,之後再進行的數據改變都只要遵守ImmutableJS的相關API即可,就可以保證數據的純凈性,每次返回的都是新的數據。與源數據的比較上就不可能會存在改變源數據相關部分之後,由於引用相等而導致數據不相等的問題。
三、在Redux中運用immutable
我在項目底下新建了一個項目目錄redux-src,同時在項目中增加了熱更新。新建了webpack.config.redux.js,專門用來處理新加的redux模塊。因此新的目錄結構如下:
webpack.config.redux.js
文件如下:
在項目中運行npm run redux,在瀏覽器輸入localhost:8888即可看到最新的模塊。這裡關於如何在react中使用redux,這裡就不多說了,如果不明白,可以去看http://cn.redux.js.org/或者到我之前寫的redux的一個小demo中去看。
重點說說如何在reducer中使用Immutable,以及在List.js中如何通過發送Action來改變store。
redux-src/redux/reducers/index.js
跟之前List.js中的state中聲明的最開始狀態一樣。這裡依舊維持一個最開始的房間列表以及一個新增房間的序號數。只不過這裡的最初狀態是通過Immutable.js處理過的,所以在reducer中的所有操作都必須按照其API來。
redux-src/components/List.js
其實這個文件也沒有作多處修改,基本可以看引入了immutabl的state管理的Detail.js。只是在操作上顯得更加簡單了。
監控圖運用Redux-DevTools工具可以清楚地看出當前redux中的數據變化,以及操作。
日誌模式:
監控模式:
總結
運用redux的好處就是全局數據可控。在redux中運用immutable data也是redux所提倡的,我們不再會因為值沒有深拷貝而找不到值在何處何時發生了變化的情況,接而引發的就是組件莫名其妙地不會re-render,同時由於immutable.js在值複製上的高效性,因此在性能上來說,會比用傳統javascript中的深拷貝上來說提升會很多。
文章摘自博客園
中公優就業IT培訓,總有你想學的:http://xue.ujiuye.com
勤工儉學計劃,0元學IT!
http://www.ujiuye.com/zt/qgjx/?wt.bd=lsh11tt
找工作太難?我們來幫你一舉拿下!
http://www.ujiuye.com/zt/jycj/?wt.bd=lsh11tt
※利用padding實現可控的分隔線
※設計模式——淺談工廠模式
※iptables對比Netfilter
※「目標檢測」PVAnet原理
※SpringMVC詳解——參數綁定
TAG:IT優就業 |
※Cambridge Analytica研究員回擊Facebook
※研究人員發現SpectrePrime和MeltdownPrime新變種
※Diabetes:新研究發現調節leptin表達的lncRNA
※Science評論「抵制Nature子刊」事件:為什麼AI研究者熱愛arXiv與OpenReview?
※Nature communications:體內活性氧研究邁出重要一步
※谷歌研究員Francois Chollet:有良知的AI研究人員不應該在Facebook工作
※New Macbook 12inch with Retina 研究性報告
※Nature Communications:核殼納米顆粒不對稱腐蝕動力學研究
※RPA軟體之Automation Anywhere研究
※研究指 Google Assistant 表現甩開 Alexa 和 Siri
※對話以太坊Casper核心研究者Karl Floersch
※Nature Communications 最新研究揭示調控種子休眠和萌發的新機制
※Science評論「抵制Nature子刊」事件:AI研究者熱愛arXiv?
※生物場療法Biofield Therapy&靈氣Reiki的科學研究進展綜述
※Facebook開源「Detectron」,用於AR研究的計算機視覺演算法!
※MIT 啟動 Intelligence Quest 計劃:研究人類智能,讓全世界的機構共同合作
※「消費者報告」New Macbook 12inch with Retina 研究性報告
※大新聞!Facebook 開源了 Python 實現的物體檢測研究平台 Detectron
※Nature再發DeepMind研究:AI復現大腦導航功能
※Cerveau Technologies, Inc.與日本東京都老人綜合研究所簽訂研究協議