您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關React中key怎么使用的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
在渲染列表時,React的差異比較算法需要一個在列表范圍內的唯一key來提高性能(通常用于獲知哪個列表項改變了)。這個唯一的key需要我們手動提供。React官方建議使用列表數據中可用于唯一性標識的字段來作為列表項渲染時的key。如果實在沒有,則可使用數組的index勉為其難,性能上可能會打折扣。
一個例子
有這樣的一個場景如下圖所示,有一組動態數量的input,可以增加和刪除和重新排序,數組元素生成的組件用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> }
首先說明的是,若頁面中數組內容是固定而不是動態的話,上面的代碼也不會有什么問題(??ˇ?ˇ?? 但是如此這也是不是推薦的做法)。
但是,動態數組導致其渲染的組件就會有問題,從上面圖中你也能看出問題:數組動態改變后,頁面上input的輸入內容跟對應的數組元素順序不對應。
為什么會這樣呢?本文后面會有解釋。react初學者對這可能更加迷惑,本文就來跟大家探討一下react的key用法,
react key概述
key的作用
react中的key屬性,它是一個特殊的屬性,它是出現不是給開發者用的(例如你為一個組件設置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認為是同一個組件,這樣后續相同的key對應組件都不會被創建。例如下面代碼:
//this.state.users內容 this.state = { users: [{id:1,name: '張三'}, {id:2, name: '李四'}, {id: 2, name: "王五"}], ....//省略 } render() return( <div> <h4>用戶列表</h4> {this.state.users.map(u => <div key={u.id}>{u.id}:{u.name}</div>)} </div> ) );
上面代碼在dom渲染掛載后,用戶列表只有張三
和李四
兩個用戶,王五
并沒有展示處理,主要是因為react根據key認為李四
和王五
是同一個組件,導致第一個被渲染,后續的會被丟棄掉。
這樣,有了key屬性后,就可以與組件建立了一種對應關系,react根據key來決定是銷毀重新創建組件還是更新組件。
key相同,若組件屬性有所變化,則react只更新組件對應的屬性;沒有變化則不更新。
key值不同,則react先銷毀該組件(有狀態組件的componentWillUnmount會執行
),然后重新創建該組件(有狀態組件的constructor
和componentWillUnmount
都會執行)
另外需要指明的是:
key不是用來提升react的性能的,不過用好key對性能是有幫組的。
key的使用場景
在項目開發中,key屬性的使用場景最多的還是由數組動態創建的子組件的情況
,需要為每個子組件添加唯一的key屬性值。
那么,為何由數組動態創建的組件必須要用到key屬性呢?這跟數組元素的動態性有關。
拿上述用戶列表的例子來說,看一下babel對上述代碼的轉換情況:
// 轉換前 const element = ( <div> <h4>用戶列表</h4> {[<div key={1}>1:張三</div>, <div key={2}>2:李四</div>]} </div> ); // 轉換后 "use strict"; var element = React.createElement( "div", null, React.createElement("h4",null,"用戶列表"), [ React.createElement("div",{ key: 1 },"1:張三"), React.createElement("div",{ key: 2 },"2:李四") ] );
有babel轉換后React.createElement
中的代碼可以看出,其它元素之所以不是必須需要key是因為不管組件的state
或者props
如何變化,這些元素始終占據著React.createElement
固定的位置,這個位置就是天然的key。
而由數組創建的組件可能由于動態的操作導致重新渲染時,子組件的位置發生了變化,例如上面用戶列表子組件新增一個用戶,上面兩個用戶的位置可能變化為下面這樣:
var element = React.createElement( "div", null, React.createElement("h4",null,"用戶列表"), [ React.createElement("div",{ key: 3 },"1:王五"), React.createElement("div",{ key: 1 },"2:張三"), React.createElement("div",{ key: 2 },"3:李四") ] );
可以看出,數組創建子組件的位置并不固定,動態改變的;這樣有了key屬性后,react就可以根據key值來判斷是否為同一組件。
另外,還有一種比較常見的場景:為一個有復雜繁瑣邏輯的組件添加key后,后續操作可以改變該組件的key屬性值,從而達到先銷毀之前的組件,再重新創建該組件。
key的最佳實踐
上面說到了,由數組創建的子組件必須有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.
可能你會發現,這只是warning而不是error,它不是強制性的,為什么react不強制要求用key而報error呢?其實是強制要求的,只不過react為按要求來默認上幫我們做了,它是以數組的index
作為key的。
index作為key是一種反模式
在list數組中,用key來標識數組創建子組件時,若數組的內容只是作為純展示,而不涉及到數組的動態變更,其實是可以使用index
作為key的。
但是,若涉及到數組的動態變更,例如數組新增元素、刪除元素或者重新排序等,這時index作為key會導致展示錯誤的數據。本文開始引入的例子就是最好的證明。
{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> // 數組重排 -> ['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>
上面實例中在數組重新排序后,key對應的實例都沒有銷毀,而是重新更新。具體更新過程我們拿key=0
的元素來說明, 數組重新排序后:
組件重新render得到新的虛擬dom;
新老兩個虛擬dom進行diff,新老版的都有key=0
的組件,react認為同一個組件,則只可能更新組件;
然后比較其children,發現內容的文本內容不同(由a--->c
),而input組件并沒有變化,這時觸發組件的componentWillReceiveProps
方法,從而更新其子組件文本內容;
因為組件的children中input組件沒有變化,其又與父組件傳入的任props
沒有關聯,所以input組件不會更新(即其componentWillReceiveProps
方法不會被執行),導致用戶輸入的值不會變化。
這就是index
作為key存在的問題,所以不要使用index作為key
。
key的值要穩定唯一
在數組中生成的每項都要有key屬性,并且key的值是一個永久且唯一的值
,即穩定唯一。
在理想情況下,在循環一個對象數組時,數組的每一項都會有用于區分其他項的一個鍵值,相當數據庫中主鍵。這樣就可以用該屬性值作為key值。但是一般情況下可能是沒有這個屬性值的,這時就需要我們自己保證。
但是,需要指出的一點是,我們在保證數組每項的唯一的標識時,還需要保證其值的穩定性,不能經常改變。例如下面代碼:
{ this.state.data.map(el=><MyComponent key={Math.random()}/>) }
上面代碼中中MyComponent的key值是用Math.random
隨機生成的,雖然能夠保持其唯一性,但是它的值是隨機而不是穩定的,在數組動態改變時會導致數組元素中的每項都重新銷毀然后重新創建,有一定的性能開銷;另外可能導致一些意想不到的問題出現。所以:
key的值要保持穩定且唯一,不能使用
random
來生成key的值。
所以,在不能使用random隨機生成key時,我們可以像下面這樣用一個全局的localCounter變量來添加穩定唯一的key值。
var localCounter = 1; this.data.forEach(el=>{ el.id = localCounter++; }); //向數組中動態添加元素時, function createUser(user) { return { ...user, id: localCounter++ } }
key其它注意事項
當然除了為數據元素生成的組件要添加key,且key要穩定且唯一之外,還需要注意以下幾點:
key屬性是添加到自定義的子組件上,而不是子組件內部的頂層的組件上。
//MyComponent ... render() {//error <div key={{item.key}}>{{item.name}}</div> } ... //right <MyComponent key={{item.key}}/>
key值的唯一是有范圍的,即在數組生成的同級同類型的組件上要保持唯一,而不是所有組件的key都要保持唯一
不僅僅在數組生成組件上,其他地方也可以使用key,主要是react利用key來區分組件的,相同的key表示同一個組件,react不會重新銷毀創建組件實例,只可能更新;key不同,react會銷毀已有的組件實例,重新創建組件新的實例。
{ this.state.type ? <div><Son_1/><Son_2/></div> : <div><Son_2/><Son_1/></div> }
例如上面代碼中,this.state.type的值改變時,原Son_1和Son2組件的實例都將會被銷毀,并重新創建Son_1和Son_2組件新的實例,不能繼承原來的狀態,其實他們只是互換了位置。為了避免這種問題,我們可以給組件加上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組件的實例沒有重新創建,react只是將他們互換位置。
感謝各位的閱讀!關于“React中key怎么使用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。