【React】ReactJS序列 組件的key

時間: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)容棘捣。親自試一試

添加之前的截圖


Paste_Image.png

添加一個節(jié)點之后的截圖


Paste_Image.png

我希望自己講得足夠清楚休建,要是不夠清楚的話乍恐,千萬要試一試评疗,不過大概實際開發(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ù)更新實踐中的感悟。

參考文章

  1. React修煉之路(一)
  2. 官方文檔:動態(tài)組件key的作用
  3. 民間文檔:進一步闡述和論證
  4. loverajoel/jstips:Github上一個每天分享js相關經(jīng)驗的項目

您可能還感興趣芍躏?

  1. 前端技術文章匯總
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末邪乍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庇楞,老刑警劉巖榜配,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吕晌,居然都是意外死亡蛋褥,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門睛驳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烙心,“玉大人,你說我怎么就攤上這事乏沸∫穑” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵蹬跃,是天一觀的道長匙瘪。 經(jīng)常有香客問我,道長炬转,這世上最難降的妖魔是什么辆苔? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮扼劈,結(jié)果婚禮上驻啤,老公的妹妹穿的比我還像新娘。我一直安慰自己荐吵,他們只是感情好骑冗,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著先煎,像睡著了一般贼涩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上薯蝎,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天遥倦,我揣著相機與錄音,去河邊找鬼占锯。 笑死袒哥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的消略。 我是一名探鬼主播堡称,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼艺演!你這毒婦竟也來了却紧?” 一聲冷哼從身側(cè)響起桐臊,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晓殊,沒想到半個月后断凶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡挺物,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年懒浮,在試婚紗的時候發(fā)現(xiàn)自己被綠了氏淑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片午磁。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡挖垛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痴昧,到底是詐尸還是另有隱情,我是刑警寧澤冠王,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布赶撰,位于F島的核電站,受9級特大地震影響柱彻,放射性物質(zhì)發(fā)生泄漏豪娜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一哟楷、第九天 我趴在偏房一處隱蔽的房頂上張望瘤载。 院中可真熱鬧,春花似錦卖擅、人聲如沸鸣奔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挎狸。三九已至,卻和暖如春断楷,著一層夾襖步出監(jiān)牢的瞬間锨匆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工冬筒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留恐锣,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓账千,卻偏偏與公主長得像侥蒙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子匀奏,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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