時間:2016-08-17 20:20:55
作者:zhongxia
概要
使用ReactJs 來構(gòu)建項目, 已經(jīng)半年多了末患,很多知識都是現(xiàn)學現(xiàn)用,從整個項目的腳手架,到項目的打包老玛,發(fā)布,并且包含項目的公共樣式钧敞,公共模塊開發(fā)蜡豹, 模塊化開發(fā)等功能。
雖然已經(jīng)可以正常的開發(fā)項目溉苛, 開發(fā)組件镜廉, 管理公共樣式等功能,但是對于 react的 diff算法 和 key之間的關系 沒有深入的了解炊昆。 只能說大概知道怎么回事桨吊,可以運用威根。
這節(jié)文章主要來記錄下 React 組件 key 相關的知識凤巨。
一、問題
在同系列的上一篇博客里洛搀,我第一次接觸組件key這個概念,因為不理解key的用處及不清楚React組件的更新機制而遇到父級組件調(diào)用了render函數(shù)而render內(nèi)的子組件內(nèi)容不更新的問題敢茁。
二、核心內(nèi)容
React是根據(jù)組件上設定的key屬性來生成該組件唯一的標識留美,只有key改變了彰檬,React才會更新組件伸刃,否則重用該組件。如果想要更新組件內(nèi)容逢倍,請保證每次的key都不一樣捧颅。
建議大家先看參考文章的:民間文檔:進一步闡述和論證,該文檔有例子演示也有相應的解決方法较雕。解決方法的核心還是這句話:如果想要更新組件內(nèi)容碉哑,請保證當前組件的key與上一狀態(tài)組件的key不同。
三亮蒋、代碼示例
1. 靜態(tài)組件
組件不是動態(tài)組件(不需要動態(tài)更新)
單純的展示組件扣典,render之后沒有交互操作。
靜態(tài)組件指定key的時候慎玖,可以直接使用 index 或者 不指定【不指定的時候贮尖,react會生成一個默認的標識】,保證key不重復即可趁怔。
2. 動態(tài)組件
組件是動態(tài)組件(需要動態(tài)更新)湿硝,
組件除了展示之后, 還有交互操作润努,比如增加一個節(jié)點图柏,刪除一個節(jié)點等功能。增加和刪除節(jié)點任连,是需要刷新組件的蚤吹,刷新的時候,React內(nèi)部的Virtual Dom 采用的 diff 算法和 key 又有關系 《留坑随抠,后期補充 diff算法講解》
刷新的依據(jù)是根據(jù)key來判斷的裁着,相同的key,React采取和上一次刷新的同樣方式拱她。
如果這個時候二驰,采用同樣的index 來作為key, 然后在列表頂部增加了一個節(jié)點秉沼, 那么新元素的key 為 0桶雀, 和上一次刷新時的舊頂部元素key 相同。此時React將認為這是這個新元素就是就頂部元素唬复,所以就按照頂部元素的內(nèi)容刷新該元素矗积,導致新元素的內(nèi)容就是以前的內(nèi)容,這個和我的預期不一致敞咧,我們預期是頂部元素顯示新的內(nèi)容棘捣。親自試一試。
添加之前的截圖
添加一個節(jié)點之后的截圖
我希望自己講得足夠清楚休建,要是不夠清楚的話乍恐,千萬要試一試评疗,不過大概實際開發(fā)都是遇到問題再去深入學習的吧,實踐越多茵烈,遇到的問題越多百匆,就能學到越多。
那么現(xiàn)在我們都知道了呜投,想要組件動態(tài)刷新胧华,只要每次刷新都賦予一個新的獨一無二的key即可,具體做法有很多種宙彪,《民間文檔:進一步闡述和論證》矩动,上面提到的文檔后面就給出了幾種方法,我沒試過释漆,大家感興趣可以去試試悲没。
我的方法,之前查閱資料想了解隨機數(shù)的生產(chǎn)原理時男图,看到這么一句話:
逝者如斯夫示姿,時間就是一個隨機數(shù)。
很有哲理味道的一句話逊笆,所以我就采取了時間作為key,那么每次生成的key都是當前時間栈戳,是獨一無二的,能確保React的動態(tài)刷新难裆。代碼如下:
上一篇博客的代碼
<form className="form-horizontal">
{this.state.list.map((todo, index) =>
<Item {...todo} key={index} />
)}
</form>
新的代碼,區(qū)別在于將 li 標簽的key由index換成當前時間
<form className="form-horizontal">
{this.state.list.map((todo) =>
<Item {...todo} key={todo.id} />
)}
</form>
乍一看是沒問題的子檀,完美解決問題,但是一運行乃戈,結(jié)果褂痰,你猜。不賣關子了症虑,直接上代碼缩歪,正確做法是這樣的。
key={new Date().getTime() + index}
1月14日更新谍憔,+new Date() 等同于 new Date().getTime()
key={+new Date() + index}
哈哈匪蝙,new Date().getTime()返回了一個精確到毫秒的時間,也就是說习贫,如果是毫秒內(nèi)的逛球,這個返回值是一樣的,也就是key一樣沈条,這是React不允許的需忿,直接報錯。而恰好你的服務器就是那么快蜡歹,每個li的生成耗時是毫秒內(nèi)的屋厘,此處的解決方法就是在該基礎上index,這樣生成的key才是獨一無二的月而。
對比之前方法的優(yōu)勢所在
雖然以前寫了下面這個函數(shù)能實現(xiàn)動態(tài)更新汗洒,但是有兩個弊端:
componentWillReceiveProps: function(nextProps,nextState) {
this.setState({
start_time: nextProps.start_time,
end_time: nextProps.end_time,
title: nextProps.title
});
}
一,倒不是代碼量的問題父款,即使以后this.setState說不定會持續(xù)增多溢谤,但最主要的還是代碼維護的問題,若采用了以前的方法憨攒,每次state的增減都要去維護componentWillReceiveProps這個方法世杀。
二,以前的方法每次都會更新所有的組件肝集,而有時候你不需要更新所有的組件瞻坝。例如,在增加一項的時候杏瞻,你并不需要更新其余項所刀,此時你只需要給新的一樣設置新的獨一無二的key,而其余項key不變即能實現(xiàn)你的業(yè)務邏輯。舉個例子吧捞挥。
render: function(){
var that = this;
return( {
this.state.items.map(function(word) {
return <Object item={word} key={word.id + ":" + word.order + ":" + (word.color || "")} />;
}) } );
}
核心內(nèi)容:
key={word.id + ":" + word.order + ":" + (word.color || "")}
可見浮创,只有id,order,color有改變的時候key才會改變,這大概就是key的意義所在吧砌函。
四斩披、其他
那天和公司里面帶我寫CMS的同事聊天,我記住了兩句話:
“我們開始用React也就半年吧讹俊,都是現(xiàn)炒現(xiàn)賣雏掠。”
“實際工作中現(xiàn)炒現(xiàn)賣會很多劣像,所以學習很重要乡话。”
最近復習周耳奕,程序大作業(yè)绑青,公司的工作內(nèi)容,挺忙的屋群,共勉闸婴,忙過了會繼續(xù)更新實踐中的感悟。