若是你用過 react,而且曾經嘗試遍歷數組來渲染一個組件,就應該遇到過上面的提示。由於提示的等級爲 Warning,而非 Error,因此不少開發同窗可能就不會去在乎,包括我本身。在前幾天開發一個須要動態渲染的組件時,才發現的了 key 的妙用,也所以打算研究下 key 究竟是幹什麼用的。html
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity.react
key 是用來幫助 react 識別哪些內容被更改、添加或者刪除。key 須要寫在用數組渲染出來的元素內部,而且須要賦予其一個穩定的值。穩定在這裏很重要,由於若是 key 值發生了變動,react 則會觸發 UI 的重渲染。這是一個很是有用的特性。算法
在相鄰的元素間,key 值必須是惟一的,若是出現了相同的 key,一樣會拋出一個 Warning,告訴相鄰組件間有重複的 key 值。而且只會渲染第一個重複 key 值中的元素,由於 react 會認爲後續擁有相同 key 的都是同一個組件。數組
雖然咱們在組件上定義了 key,可是在其子組件中,咱們並無辦法拿到 key 的值,由於 key 僅僅是給 react 內部使用的。若是咱們須要使用到 key 值,能夠經過其餘方式傳入,好比將 key 值賦給 id 等。ide
arr.map(item => <Component key={item.id} id={item.id} />)
複製代碼
不少時候,咱們可能並無在遍歷數組渲染組件的時候寫上 key 的習慣,由於除了控制檯報到一個 Warning,並不會有任何影響。由於賦 key 值這一步 react 幫咱們作了,默認使用的是遍歷過程當中的 index 值。post
let arr = ['first', 'second'];
// list1 和 list2 是等價的
const list1 = arr.map(item => <p>{item}</p>);
const list2 = arr.map((item, index) => <p key={index}>{item}</p>);
複製代碼
在上面的例子中,若是數組發生了變化,咱們須要在數組的末尾插入一個元素 arr.push('third')
,react 通過 diff 後就會發現 :key 值爲0和1的元素並無發生如何變化,因此 react 會認爲, 最後須要在 UI 上發生變動,僅僅是插入一個 key 值爲2的新元素。性能
可是若是咱們在數組的開頭插入了一個新元素arr.unshift('zero')
,react 通過 diff 後就會發現每個元素的 key 值都發生了變化,也是就說每一個元素都要從新渲染一次,雖然從結果來看,僅僅是在開頭添加了一個元素而已。若是負責渲染的數組數據量較大的話,則會對性能形成較大的影響。與 react 使用的啓發式算法是相悖的。spa
<!-- before -->
<p key="0">first</p>
<p key="1">second</p>
<!-- after -->
<p key="0">zero</p>
<p key="1">first</p>
<p key="2">second</p>
複製代碼
所以,推薦的作法是每一個兄弟元素都加上一個穩定惟一的 key 值。code
主要應用在 dynamic stateful components中,也就是須要動態渲染的子組件。component
下圖是一個名爲 Filters
的組件,內部由一個個condition
子組件組成,由 defaultValue
負責初始化渲染。defaultValue
的值可由組件生成,能夠經過 onChange
事件獲取,默認不傳爲空數組。經過將以前保存好的值回傳給組件,便可渲染須要的 Filters
。
const defalutValue = [{
id: 1515134128441,
tag: 'mobile', // 手機號 決定最後須要使用的 input 輸入框
flag: [
'身份標籤',
`{"code":"location_province_code","valueType":"area_province"}`
], // 決定第一級 級聯選框 的默認值
operator: "neq", // 操做符
target: "00001" // input 輸入框的值
}, {
...
}]
複製代碼
這裏遇到的問題是,condition
子組件的內部已經比較複雜了,須要處理多種狀況:
在上述狀況中,若是condition
要實現接收不一樣的默認值來展現不一樣的效果,則須要寫一系列複雜的 componentWillReceiveProps
生命週期。並且不能保證代碼的可讀性以及維護性,是一個很可怕的事情。
可是,若是你在用 defaultValue
渲染每一個 Condition
的時候,給它加一個惟一穩定的 key 值,就能夠完美解決這個問題。我在實現的過程當中,用了當前時間戳做爲Condition
的 key 值,保證其惟一穩定性。在刪除、增長標籤都能確保正確渲染。若是沒有 key 值也沒有寫componentWillReceiveProps
生命週期,在刪除的時候就會發生渲染錯誤。
簡而言之,改變 key 值來重渲染組件是一種——相較於複雜componentWillReceiveProps
生命週期——十分低成本的方式。
自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)