React中的key

                前言:( ⊙ o ⊙ )啊!最近簡歷投得很不順利呀,感覺是項目經驗不符合互聯網公司的需求........╮(╯▽╰)╭沒辦法,在公司做得最多的就是業務邏輯的代碼,雖然知道這一點,自己在加緊學習,但是結果還是不盡如人意,畢竟沒做過真正的項目別人是很少會"冒險".......也罷,《盜鑰匙的方法》中的”殺手“成了我目前的一個”精神“支柱!

在參考官網的文檔學習React中,其實有關於key的講解,但是自己覺得有點晦澀,當時就沒怎麼看;到後來在做一個例子的時候:商品的表格,提供了簡單的查詢功能;我在自己實現的過程中,發現”key“這個關鍵詞在react中是比較重要的一個概念,而且後面自己想對價格排序的時候發現在這個"key"上屢屢受挫,只好自己總結一下了。(出來混,總得要還的呀!)


github:https://github.com/liuzaijiang/React-text

下一篇文章:http://blog.csdn.net/liuzijiang1123/article/details/69569556(是在這個demo基礎上進行再加工)

我相信大部分人都是參考網上的這篇文章學習的:http://taobaofed.org/blog/2016/08/24/react-key/



一千個讀者就有一千個哈姆雷特嘛,我也來學習學習!

首先是概念:

React 元素可以具有一個特殊的屬性 key,這個屬性不是給用戶自己用的,而是給 React 自己用的。如果我們動態地創建 React 元素,而且 React 元素內包含數量或順序不確定的子元素時,我們就需要提供 key 這個特殊的屬性。(大多我們用的地方是渲染數組中的元素,例如表格,li等)



OK,接下來是我根據官網例子加上自己的實現,對於這個key的理解。

在官網,有個例子中就是渲染一個商品的價格表格,你打開F12後會發現:

Warning: flattenChildren(...): Encountered two children with the same key

是因爲每個td是放在一個數組中,但是並沒有給每個td賦一個唯一的key值屬性,解決方法就是:

rows.push(<ProductRow product={product} key={product.name} />);

我這裏賦的key是每個商品的name(唯一),不管賦什麼都是要保證一個唯一性;(當然還要有一定的技巧性,這個後面操作表格數據的時候會用到。)


這個key值是用來幹嘛的呢?

當我們組件狀態更新後,會重新渲染組件,渲染組件的時候會一個個去根據key值的情況去渲染:

A. 渲染前的key值存在,則去尋找這個key值對應的組件:

        a.組件數據不變,則不重新渲染這個組件;

        b.若組件數據改變,則渲染改變的這一部分數據;

B.渲染前的key值不存在,則會銷燬這個key值對應的組件:

C.出現新的key值,則渲染一個新的key值對應的組件;



有了上面的這些總結,其實我們就可以對錶格進行操作了:增,刪,改。


增:

 如果想增加一個商品,我們只需要在保存商品的數組中增加這個商品的對象即可,然後爲這個數據去添加一個新的key值,這樣狀態改變的時候就會把這個新商品渲染進表格;


刪:

 如果想刪除一個商品,我們只需要將這個商品在這個數組中去掉,這樣key值也會隨之沒有,渲染的時候這個商品也不會渲染出來;不過我們怎麼去尋找到這個商品呢?

這裏我們就要利用到key值的一個技巧,上面提到了我給每個商品的 key值賦值的是每個商品的name(唯一),一般都來說都是賦的是index值,就是每個商品在數組中存在的索引值。但是這樣不好,爲什麼?因爲我們商品會去排序,這樣你的順序就會被打亂。如果是用name值得話,我們可以很精確的找到,然後配合filter方法來篩選出被刪除後的數組。

而且我們是不能通過this.props.key獲取這個key值的,所以這裏就再爲組件定義一個屬性,賦值name,這樣我們獲得這個屬性的值,就相當於獲得了key值。


流程:首先我們在渲染的時候給每個商品的"刪除功能的td元素上"賦值一個name屬性,值就是我們的商品name;

          然後我們通過click事件的回調函數中的參數event來獲取這個name值,event.target.name;

          再把這個值在商品的數組中通過filter方法,來篩選出除了這個值的其他商品,這樣剩下的就是被刪除後的數組,我們需要渲染的商品;

          最後更新一下狀態,渲染表格;


改:

   修改商品和我們刪除商品其實大致思路是一樣的,只不過稍微多了一些步驟,當我們用filter篩選出了我們需要修改的對象的時候,同時還需要獲得它在這個數組中的index(索引),然後再修改其數據,更新狀態。


當然,我們修改商品的時候我這邊是彈出一個框,然後還需要把商品本身的情況先進行賦值,我們這裏需要用到ref這個屬性,獲取我們真實的DOM節點,比如<input/>這些,但是這裏需要注意的就是,ref在render中是無法使用的,因爲必須要等組件掛載後才能獲取到值,那我們如何爲組件預先賦值呢?很簡單,使用defaultValue這個屬性。

<input ref='modifyCategory' id='staffModifyName' type='text' defaultValue={modifyProduct[0].category}/>
這樣就行,這個是修改商品,如果是新加商品的話,我們還是用value就行了。



額外:

如果每次渲染的時候想每個組件都刷新(重新渲染)的話,就給這個key值賦一個變量;

rows.push(<ProductRow product={product}  key={+new Date() + i} />);

賦一個當前時間加索引,這樣每次狀態變化的時候,組件都會去重新渲染。


官網提供的那個表格的例子其實比較簡陋,還有一個BUG:


let product = [
  {category: 'Sporting Goods', price: 49.99, stocked: true, name: 'Football'},
  {category: 'Sporting Goods', price: 9.99, stocked: true, name: 'Baseball'},
  {category: 'Sporting Goods', price: 29.99, stocked: false, name: 'Basketball'},
  {category: 'Electronics', price: 99.99, stocked: true, name: 'iPod Touch'},
  {category: 'Electronics', price: 399.99, stocked: false, name: 'iPhone 5'},
  {category: 'Electronics', price: 199.99, stocked: true, name: 'Nexus 7'}
];


仔細可以發現,它的商品類別category都是分類好了,按順序寫進了數組,然後表格顯示的時候是

Sporting Goods

 xxxxxx

 xxxxxx

 xxxxxx

Electronics

 xxxxxx

 xxxxxx

 xxxxxx


每個商品種類也是一行,這樣也會有一個key值,如果把數組的順序打亂的話,會出現下面這種情況,而且它的商品種類的key都是用的商品的category,這樣會出現key值不唯一的情況,我解決了key值不唯一的情況,這個排列有問題的還沒有解決,而且做價格排序的話也很有值得思考的地方,到底是按所有商品的價格排序,還是按每個種類的商品排序呢?值得去思考


  

Sporting Goods

 xxxxxx

 xxxxxx

Electronics

xxxxxx

xxxxxx

xxxxxx

Sporting Goods

 xxxxxx







發佈了128 篇原創文章 · 獲贊 54 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章