ReactJS修煉之路(二):組件的key

一,概要

在同系列的上一篇博客React修煉之路(一)裏,我第一次接觸組件key這個概念,因爲不理解key的用處及不清楚React組件的更新機制而遇到父級組件調用了render函數而render內的子組件內容不更新的問題。

React修煉之路(一)裏我在子組件裏使用了componentWillReceiveProps方法,實現了內容更新,具體內容參見上一篇博客。

最近又看了一些資料,同時實踐得更多,對這個問題有了新的理解,下面簡單說說。

二,學習資料

慣例,先上資料:

核心內容: React是根據組件上設定的key屬性來生成該組件唯一的標識,只有key改變了,React纔會更新組件,否則重用該組件。如果想要更新組件內容,請保證每次的key都不一樣。

建議大家先看第二個文檔:民間文檔:進一步闡述和論證,該文檔有例子演示也有相應的解決方法。解決方法的核心還是這句話:如果想要更新組件內容,請保證當前組件的key與上一狀態組件的key不同。

三,代碼示例

React修煉之路(一)裏面實現組件更新的方法就不說了,這裏說說上面文檔給我的啓發。首先要明確自己的業務需求。

  • 你的組件不是動態組件(不需要動態更新),例如你一個列表只做展示,第一次render出來後就不會改變裏面的內容,那麼你不需要指定key(不指定key時,React也會生成一個默認的標識),或者將index作爲key,只要key不重複即可。

  • 你的組件是動態組件(需要動態更新),例如你一個列表做展示時,能向列表添加或刪除元素,此時組件是需要刷新的,刷新的依據就是key,對於相同的key,React會採取和上一次刷新同樣的方式。這個時候,如果你採取index作爲key,那麼假設你在列表頂部添加了元素,那麼新的元素的key就是index=0,和上一次刷新時舊頂部元素的key相同,此時React將認爲這是這個新元素就是就頂部元素,所以就按照頂部元素的內容刷新該元素,導致新元素的內容就是以前的內容,這個和我的預期不一致,我們預期是頂部元素顯示新的內容。親自試一試

  • 我希望自己講得足夠清楚,要是不夠清楚的話,千萬要試一試,不過大概實際開發都是遇到問題再去深入學習的吧,實踐越多,遇到的問題越多,就能學到越多。

那麼現在我們都知道了,想要組件動態刷新,只要每次刷新都賦予一個新的獨一無二的key即可,具體做法有很多種,民間文檔:進一步闡述和論證,上面提到的文檔後面就給出了幾種方法,我沒試過,大家感興趣可以去試試。

我的方法,之前查閱資料想了解隨機數的生產原理時,看到這麼一句話:

逝者如斯夫,時間就是一個隨機數。

當前時間

很有哲理味道的一句話,所以我就採取了時間作爲key,那麼每次生成的key都是當前時間,是獨一無二的,能確保React的動態刷新。代碼如下:

上一篇博客的代碼

render: function(){
    var that = this;
    return(
        <ul>
        {
          this.state.programs.map(function(program,index) {
            return <li key={index} className="channel-program">
            <ChannelProgram program_index={index} day={that.props.day} change={that.props.change} bill={program}/>
            </li>;
          })
        }
        </ul>
    );
  }

新的代碼,區別在於將 li 標籤的key由index換成當前時間

render: function(){
    var that = this;
    return(
        <ul>
        {
          this.state.programs.map(function(program,index) {
            return <li key={new Date().getTime()} className="channel-program">
            <ChannelProgram program_index={index} day={that.props.day} change={that.props.change} bill={program}/>
            </li>;
          })
        }
        </ul>
    );
  }

乍一看是沒問題的,完美解決問題,但是一運行,結果,你猜。不賣關子了,直接上代碼,正確做法是這樣的。

key={new Date().getTime() + index}

1月14日更新,+new Date() 等同於 new Date().getTime()

key={+new Date() + index}

哈哈,new Date().getTime()返回了一個精確到毫秒的時間,也就是說,如果是毫秒內的,這個返回值是一樣的,也就是key一樣,這是React不允許的,直接報錯。而恰好你的服務器就是那麼快,每個li的生成耗時是毫秒內的,此處的解決方法就是在該基礎上index,這樣生成的key纔是獨一無二的。

對比之前方法的優勢所在

雖然以前寫了下面這個函數能實現動態更新,但是有兩個弊端:

componentWillReceiveProps: function(nextProps,nextState) {
    this.setState({
      start_time: nextProps.start_time,
      end_time: nextProps.end_time,
      title: nextProps.title
    });
  }
  • 一,倒不是代碼量的問題,即使以後this.setState說不定會持續增多,但最主要的還是代碼維護的問題,若採用了以前的方法,每次state的增減都要去維護componentWillReceiveProps這個方法。

  • 二,以前的方法每次都會更新所有的組件,而有時候你不需要更新所有的組件。例如,在增加一項的時候,你並不需要更新其餘項,此時你只需要給新的一樣設置新的獨一無二的key,而其餘項key不變即能實現你的業務邏輯。舉個例子吧。

render: function(){
    var that = this;
    return(
          {
            this.state.items.map(function(word) {
              return <Object item={word}
                key={word.id + ":" + word.order + ":" + (word.color || "")} />;
            })
          }
    );
  }

核心內容:

key={word.id + ":" + word.order + ":" + (word.color || "")}

可見,只有id,order,color有改變的時候key纔會改變,這大概就是key的意義所在吧。

四,其他

那天和公司裏面帶我寫CMS的同事聊天,我記住了兩句話:

“我們開始用React也就半年吧,都是現炒現賣。”

“實際工作中現炒現賣會很多,所以學習很重要。”

最近複習周,程序大作業,公司的工作內容,挺忙的,共勉,忙過了會繼續更新實踐中的感悟。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章