欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解React之key的使用和實踐

 更新時間:2018年09月29日 13:47:11   作者:wonyun  
這篇文章主要介紹了詳解React之key的使用和實踐,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

在渲染列表時,React的差異比較算法需要一個在列表范圍內(nèi)的唯一key來提高性能(通常用于獲知哪個列表項改變了)。這個唯一的key需要我們手動提供。React官方建議使用列表數(shù)據(jù)中可用于唯一性標識的字段來作為列表項渲染時的key。如果實在沒有,則可使用數(shù)組的index勉為其難,性能上可能會打折扣。

一個例子

有這樣的一個場景如下圖所示,有一組動態(tài)數(shù)量的input,可以增加和刪除和重新排序,數(shù)組元素生成的組件用index作為key的值,例如下圖生成的ui展示:


上面例子中的input組件渲染的代碼如下所示,全部完整代碼可以參考 ==>完整code。

{this.state.data.map((v,idx)=><Item key={idx} v={v} />)}

//Item組件render方法
render(){
  return <li>{this.props.v} <input type="text"/></li>
}

首先說明的是,若頁面中數(shù)組內(nèi)容是固定而不是動態(tài)的話,上面的代碼也不會有什么問題(。•ˇ‸ˇ•。 但是如此這也是不是推薦的做法)。

但是,動態(tài)數(shù)組導致其渲染的組件就會有問題,從上面圖中你也能看出問題:數(shù)組動態(tài)改變后,頁面上input的輸入內(nèi)容跟對應的數(shù)組元素順序不對應。

為什么會這樣呢?本文后面會有解釋。react初學者對這可能更加迷惑,本文就來跟大家探討一下react的key用法,

react key概述

key的作用

react中的key屬性,它是一個特殊的屬性,它是出現(xiàn)不是給開發(fā)者用的(例如你為一個組件設置key之后不能獲取組件的這個key props),而是給react自己用的。

那么react是怎么用key的呢?react的作者之一Paul O'Shannessy有提到:

Key is not really about performance, it's more about identity (which in turn leads to better performance). Randomly assigned and changing values do not form an identity

簡單來說,react利用key來識別組件,它是一種身份標識標識,就像我們的身份證用來辨識一個人一樣。每個key對應一個組件,相同的key react認為是同一個組件,這樣后續(xù)相同的key對應組件都不會被創(chuàng)建。例如下面代碼:

//this.state.users內(nèi)容
this.state = {
 users: [{id:1,name: '張三'}, {id:2, name: '李四'}, {id: 2, name: "王五"}],
 ....//省略
}
render()
 return(
 <div>
  <h3>用戶列表</h3>
  {this.state.users.map(u => <div key={u.id}>{u.id}:{u.name}</div>)}
 </div>
 )
);

上面代碼在dom渲染掛載后,用戶列表只有張三李四兩個用戶,王五并沒有展示處理,主要是因為react根據(jù)key認為李四王五是同一個組件,導致第一個被渲染,后續(xù)的會被丟棄掉。

這樣,有了key屬性后,就可以與組件建立了一種對應關系,react根據(jù)key來決定是銷毀重新創(chuàng)建組件還是更新組件。

  • key相同,若組件屬性有所變化,則react只更新組件對應的屬性;沒有變化則不更新。
  • key值不同,則react先銷毀該組件(有狀態(tài)組件的componentWillUnmount會執(zhí)行),然后重新創(chuàng)建該組件(有狀態(tài)組件的constructorcomponentWillUnmount都會執(zhí)行)

另外需要指明的是:

key不是用來提升react的性能的,不過用好key對性能是有幫組的。

key的使用場景

在項目開發(fā)中,key屬性的使用場景最多的還是由數(shù)組動態(tài)創(chuàng)建的子組件的情況,需要為每個子組件添加唯一的key屬性值。

那么,為何由數(shù)組動態(tài)創(chuàng)建的組件必須要用到key屬性呢?這跟數(shù)組元素的動態(tài)性有關。

拿上述用戶列表的例子來說,看一下babel對上述代碼的轉(zhuǎn)換情況:

// 轉(zhuǎn)換前
const element = (
 <div>
  <h3>用戶列表</h3>
  {[<div key={1}>1:張三</div>, <div key={2}>2:李四</div>]}
 </div>
);

// 轉(zhuǎn)換后
"use strict";

var element = React.createElement(
 "div",
 null,
 React.createElement("h3",null,"用戶列表"),
 [
  React.createElement("div",{ key: 1 },"1:張三"), 
  React.createElement("div",{ key: 2 },"2:李四")
 ]
);

有babel轉(zhuǎn)換后React.createElement中的代碼可以看出,其它元素之所以不是必須需要key是因為不管組件的state或者props如何變化,這些元素始終占據(jù)著React.createElement固定的位置,這個位置就是天然的key。

而由數(shù)組創(chuàng)建的組件可能由于動態(tài)的操作導致重新渲染時,子組件的位置發(fā)生了變化,例如上面用戶列表子組件新增一個用戶,上面兩個用戶的位置可能變化為下面這樣:

var element = React.createElement(
 "div",
 null,
 React.createElement("h3",null,"用戶列表"),
 [
  React.createElement("div",{ key: 3 },"1:王五"), 
  React.createElement("div",{ key: 1 },"2:張三"), 
  React.createElement("div",{ key: 2 },"3:李四")
 ]
);

可以看出,數(shù)組創(chuàng)建子組件的位置并不固定,動態(tài)改變的;這樣有了key屬性后,react就可以根據(jù)key值來判斷是否為同一組件。

另外,還有一種比較常見的場景:為一個有復雜繁瑣邏輯的組件添加key后,后續(xù)操作可以改變該組件的key屬性值,從而達到先銷毀之前的組件,再重新創(chuàng)建該組件。

key的最佳實踐

上面說到了,由數(shù)組創(chuàng)建的子組件必須有key屬性,否則的話你可能見到下面這樣的warning:

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `ServiceInfo`. See https://fb.me/react-warning-keys for more information.

可能你會發(fā)現(xiàn),這只是warning而不是error,它不是強制性的,為什么react不強制要求用key而報error呢?其實是強制要求的,只不過react為按要求來默認上幫我們做了,它是以數(shù)組的index作為key的。

index作為key是一種反模式

在list數(shù)組中,用key來標識數(shù)組創(chuàng)建子組件時,若數(shù)組的內(nèi)容只是作為純展示,而不涉及到數(shù)組的動態(tài)變更,其實是可以使用index作為key的。

但是,若涉及到數(shù)組的動態(tài)變更,例如數(shù)組新增元素、刪除元素或者重新排序等,這時index作為key會導致展示錯誤的數(shù)據(jù)。本文開始引入的例子就是最好的證明。

{this.state.data.map((v,idx)=><Item key={idx} v={v} />)}
// 開始時:['a','b','c']=>
<ul>
  <li key="0">a <input type="text"/></li>
  <li key="1">b <input type="text"/></li>
  <li key="2">c <input type="text"/></li>
</ul>

// 數(shù)組重排 -> ['c','b','a'] =>
<ul>
  <li key="0">c <input type="text"/></li>
  <li key="1">b <input type="text"/></li>
  <li key="2">a <input type="text"/></li>
</ul>

上面實例中在數(shù)組重新排序后,key對應的實例都沒有銷毀,而是重新更新。具體更新過程我們拿key=0的元素來說明, 數(shù)組重新排序后:

  • 組件重新render得到新的虛擬dom;
  • 新老兩個虛擬dom進行diff,新老版的都有key=0的組件,react認為同一個組件,則只可能更新組件;
  • 然后比較其children,發(fā)現(xiàn)內(nèi)容的文本內(nèi)容不同(由a--->c),而input組件并沒有變化,這時觸發(fā)組件的componentWillReceiveProps方法,從而更新其子組件文本內(nèi)容;
  • 因為組件的children中input組件沒有變化,其又與父組件傳入的任props沒有關聯(lián),所以input組件不會更新(即其componentWillReceiveProps方法不會被執(zhí)行),導致用戶輸入的值不會變化。

這就是index作為key存在的問題,所以不要使用index作為key。

key的值要穩(wěn)定唯一

在數(shù)組中生成的每項都要有key屬性,并且key的值是一個永久且唯一的值,即穩(wěn)定唯一。

在理想情況下,在循環(huán)一個對象數(shù)組時,數(shù)組的每一項都會有用于區(qū)分其他項的一個鍵值,相當數(shù)據(jù)庫中主鍵。這樣就可以用該屬性值作為key值。但是一般情況下可能是沒有這個屬性值的,這時就需要我們自己保證。

但是,需要指出的一點是,我們在保證數(shù)組每項的唯一的標識時,還需要保證其值的穩(wěn)定性,不能經(jīng)常改變。例如下面代碼:

{
  this.state.data.map(el=><MyComponent key={Math.random()}/>)
}

上面代碼中中MyComponent的key值是用Math.random隨機生成的,雖然能夠保持其唯一性,但是它的值是隨機而不是穩(wěn)定的,在數(shù)組動態(tài)改變時會導致數(shù)組元素中的每項都重新銷毀然后重新創(chuàng)建,有一定的性能開銷;另外可能導致一些意想不到的問題出現(xiàn)。所以:

key的值要保持穩(wěn)定且唯一,不能使用random來生成key的值。

所以,在不能使用random隨機生成key時,我們可以像下面這樣用一個全局的localCounter變量來添加穩(wěn)定唯一的key值。

var localCounter = 1;
this.data.forEach(el=>{
  el.id = localCounter++;
});
//向數(shù)組中動態(tài)添加元素時,
function createUser(user) {
  return {
    ...user,
    id: localCounter++
  }
}

key其它注意事項

當然除了為數(shù)據(jù)元素生成的組件要添加key,且key要穩(wěn)定且唯一之外,還需要注意以下幾點:

key屬性是添加到自定義的子組件上,而不是子組件內(nèi)部的頂層的組件上。

//MyComponent
...
render() {//error
  <div key={{item.key}}>{{item.name}}</div>
}
...

//right
<MyComponent key={{item.key}}/>

key值的唯一是有范圍的,即在數(shù)組生成的同級同類型的組件上要保持唯一,而不是所有組件的key都要保持唯一

不僅僅在數(shù)組生成組件上,其他地方也可以使用key,主要是react利用key來區(qū)分組件的,相同的key表示同一個組件,react不會重新銷毀創(chuàng)建組件實例,只可能更新;key不同,react會銷毀已有的組件實例,重新創(chuàng)建組件新的實例。

{
 this.state.type ? 
  <div><Son_1/><Son_2/></div>
  : <div><Son_2/><Son_1/></div>
}

例如上面代碼中,this.state.type的值改變時,原Son_1和Son2組件的實例都將會被銷毀,并重新創(chuàng)建Son_1和Son_2組件新的實例,不能繼承原來的狀態(tài),其實他們只是互換了位置。為了避免這種問題,我們可以給組件加上key。

{
 this.state.type ? 
  <div><Son_1 key="1"/><Son_2 key="2"/></div>
  : <div><Son_2 key="2" /><Son_1 key="1"/></div>
}

這樣,this.state.type的值改變時,Son_1和Son2組件的實例沒有重新創(chuàng)建,react只是將他們互換位置。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • React Fiber中面試官最關心的技術(shù)話題

    React Fiber中面試官最關心的技術(shù)話題

    這篇文章主要為大家介紹了React Fiber中面試官最關心的技術(shù)話題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • react實現(xiàn)同頁面三級跳轉(zhuǎn)路由布局

    react實現(xiàn)同頁面三級跳轉(zhuǎn)路由布局

    這篇文章主要為大家詳細介紹了react實現(xiàn)同頁面三級跳轉(zhuǎn)路由布局,一個路由小案例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • react中使用useEffect及踩坑記錄

    react中使用useEffect及踩坑記錄

    這篇文章主要介紹了react中使用useEffect及踩坑記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 使用react context 實現(xiàn)vue插槽slot功能

    使用react context 實現(xiàn)vue插槽slot功能

    這篇文章主要介紹了使用react context 實現(xiàn)vue插槽slot功能,文中給大家介紹了vue的slot的實現(xiàn)方法,需要的朋友可以參考下
    2019-07-07
  • Can't?perform?a?React?state?update?on?an?unmounted?component報錯解決

    Can't?perform?a?React?state?update?on?an?unmoun

    這篇文章主要為大家介紹了Can't?perform?a?React?state?update?on?an?unmounted?component報錯解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 深入淺析react native es6語法

    深入淺析react native es6語法

    這篇文章主要介紹了深入淺析react native es6語法的相關資料,需要的朋友可以參考下
    2015-12-12
  • React?Suspense前后端IO異步操作處理

    React?Suspense前后端IO異步操作處理

    這篇文章主要為大家介紹了React?Suspense前后端IO異步操作處理示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • 教你react中如何理解usestate、useEffect副作用、useRef標識和useContext

    教你react中如何理解usestate、useEffect副作用、useRef標識和useContext

    這篇文章主要介紹了react中如何理解usestate、useEffect副作用、useRef標識和useContext,其實與vue中的ref和reactive一樣,通過useState獲取到的數(shù)據(jù)可以實現(xiàn)組件視圖實時交互,而普通定義的數(shù)據(jù)僅僅在業(yè)務中使用,需要的朋友可以參考下
    2022-11-11
  • React中使用Echarts無法顯示title、tooltip等組件的解決方案

    React中使用Echarts無法顯示title、tooltip等組件的解決方案

    這篇文章主要介紹了React中使用Echarts無法顯示title、tooltip等組件的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • React commit源碼分析詳解

    React commit源碼分析詳解

    前兩章講到了,react 在 render 階段的 completeUnitWork 執(zhí)行完畢后,就執(zhí)行 commitRoot 進入到了 commit 階段,本章將講解 commit 階段執(zhí)行過程源碼
    2022-11-11

最新評論