react本身就非常關注效能,其提供的虛擬dom搭配上diff演算法,實現對dom操作最小粒度的改變也是非常高效的,然而其元件的渲染機制,也決定了在對元件更新時還可以進行更細緻的優化。
在講react生命週期時,就談到過react元件分為了初始化渲染和更新渲染,初始化渲染會呼叫根元件下的所有元件的render方法進行渲染, 如下圖所示(綠色表示已經渲染):
但是,當我們要更新某個元件的時候,如下面的綠色元件(從根元件傳遞下來應用在綠色元件上的資料發生變化)
即在這三層中,只有最底下的一層中的某個綠色元件的資料發生變化,所以理想狀態就是只呼叫關鍵路徑元件上的render,如下圖:
但是 react 的預設做法是呼叫所有元件的render,再對生成的虛擬dom進行比對,如果不變則不進行更新,這樣的reader和虛擬dom的對比是在浪費,如下圖(黃色表示浪費的render和虛擬dom的對比)
(橘黃色 = 浪費的渲染)
哦,不!我們所有的節點都被重新渲染了。
注意: 每次更新的方式是: 如果狀態發生改變,就先render,render的過程是生成虛擬dom的過程,然後在拿這個虛擬dom和上一次的虛擬dom進行比對,生成乙個patch,通過這個patch打到真實dom上,得到更新,雖然,通過虛擬dom,react很好的做到了dom的更新很少,但是,在狀態發生變化的時候,react在render的時候卻整個(所有的元件)都render了,而不是render一部分(最好只render狀態發生變化的那個元件),這樣就造成了浪費。那麼如何才能避免發生這個浪費問題呢? 這裡就要遷出我們的 shouldcomponentupdate 了。
在上面我們說到了在某乙個元件更新的時候,只需要這乙個元件呼叫render方法就可以了,而其他的元件不需要呼叫render方法(即使通過比對發現dom沒有改變,則不更新dom,但是比對的時間也是被浪費了),那麼怎麼做到呢?實際上,react在每個元件生命週期更新的時候都會呼叫乙個 shouldcomponentupdate(nextprops, nextstate)函式, 他的職責就是返回true或false, true表示需要更新,而false表示不需要更新,預設返回true。即使你沒有顯示的定義這個shouldcomponentupdate函式,那麼返回的就是true,一定需要發生重新渲染,這樣也就不安理解為什麼會發生上面的資源浪費了 。
為了避免一定程度的浪費,react官方還在0.14版本中新增了無狀態元件,如下所示:
//es5function hellomessage(props)
;}
//因為無狀態元件壓根就沒有涉及到狀態的改變,那麼他們是不會參與到每次render和比對虛擬dom的過程的,而是一旦建立,就穩如泰山了。es6const hellomessage = (props) => hello
;
比如,下面時乙個音量圖示,這是乙個svg圖示,不需要更新,所以在shouldcomponentupdate中直接return false, 如下:
import react, from這樣,無論上面的狀態發生了怎樣的改變,這裡直接return false,所以就不會有render的過程了,避免了效能上的消耗和浪費。其實,這樣的情況直接使用無狀態元件會更好,就不會有這個判斷。先來個官網的例子,通過判斷id是否改變來確定是否需要更新:'react';
class
mic extends component
shouldcomponentupdate()
render()
}export
default mic;
shouldcomponentupdate: function(nextprops, nextstate)是不是很簡單呢?但是是不是所有的都可以直接這麼對比呢? 我們來看下js的兩種資料型別的比較:
//我們可以看到 a 和 b 不等,但是c和d是相等的,因為對於引用型別,比較的時位址,這裡的位址並乜有發生改變!所以,我們得分情況處理了,原始資料型別和應用型別得採用不同的方法處理。原始資料型別:原始資料的比對很簡單,我們直接比對就是了,但是我們還可以更簡單的比對,因為每乙個元件這麼寫下去也是挺麻煩的,於是react官方有了外掛程式幫助我們搞定這件事:原始型別
var a = '
hello the';
var b =a;
b = b + '
world';
console.log(a === b); //
false
//引用型別
var c = ['
hello
', '
the'
];var d =c;
d.push(
'world');
console.log(c === d); //
true
var purerendermixin = require('react-addons-pure-render-mixin');
react.createclass(>foo
; }
});
var shallowcompare = require('引用型別資料:react-addons-shallow-compare');
export
class
samplecomponent extends react.component
render() >foo
; }
}
var update = require('這樣,newdate和mydate就可以比對了。react-addons-update');
var newdata =update(mydata, }},
a: }
});
const newvalue =;immutable data 就是一旦建立,就不能再被更改的資料。對 immutable 物件的任何修改或新增刪除操作都會返回乙個新的 immutable 物件。//快速檢查 —— 只要檢查引用
newvalue === oldvalue; //
false
//如果你願意也可以用 object.assign 語法
const newvalue2 =object.assign({}, oldvalue);
newvalue2 === oldvalue; //
false
immutable 實現的原理是 persistent data structure(持久化資料結構),也就是使用舊資料建立新資料時,要保證舊資料同時可用且不變。同時為了避免 deepcopy 把所有節點都複製一遍帶來的效能損耗,immutable 使用了 structural sharing(結構共享),即如果物件樹中乙個節點發生變化,只修改這個節點和受它影響的父節點,其它節點則進行共享,這樣,就是每次開闢了新的位址,但是其中的某個屬性還是在對之前沒有改變的資料作引用,這樣的效能消耗,就會減少。請看下面動畫:
immutable.js 可以很好的解決問題,他的基本原則是對於不變的物件返回相同的引用,對於變化的物件,返回新的引用, 因此對於狀態的比較只要使用如下**:
shouldcomponentupdate()
如何對Android進行效能優化
android的效能優化多少能代表乙個程式設計師的級別,如果面試的時候,面試官問到你,你是如何對android進行效能優化的,你若簡單的敷衍兩句,那基本認定你就是個初級的程式設計師了。所以作為資深的android工程師,了解效能優化是我們要走的第一步。主要方式布局優化 繪製優化 記憶體洩漏優化 li...
React 效能優化
避免重複渲染 當乙個元件的props或者state改變時,react通過比較新返回的元素和之前渲染的元素來決定是否有必要更新實際的dom。當他們不相等時,react會更新dom。在一些情況下,你的元件可以通過重寫這個生命週期函式shouldcomponentupdate來提公升速度,它是在重新渲染過...
react 效能優化
在shouldcomponentupdate 方法中判斷props和state是否改變,若未改變則無需渲染。有些情況如父元件的props或state改變了,但是子元件其實未改變,若不判斷的話會導致子元件一起被渲染。shouldcomponentupdate nextprops nextstate r...