您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關(guān)React中key的作用有哪些,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
要了解React中key的作用,可以從key的取值入手,key的取值可以分為三種,不定值、索引值、確定且唯一值
在下面的代碼中,key的取值是不定值(Math.random())
import React, { useState } from 'react'; function App() { const [initMap, setInitMap] = useState([1,2,3,4]); const handleClick = () => { setInitMap([1,2,3,4]) var spanEle = document.getElementsByTagName('span'); Array.from(spanEle).map(it => it.style.color = 'red') } return ( <div className="App" id="app"> { initMap.map((it,index) => <div key={Math.random()}><span>color</span></div>) } <button onClick={() => handleClick()}></button> </div> ); } export default App;
答案是:不會
這個問題涉及react渲染機制和diff算法
官網(wǎng)中對于diff有如下規(guī)則:
當元素類型變化時,會銷毀重建
當元素類型不變時,對比屬性
當組件元素類型不變時,通過props遞歸判斷子節(jié)點
遞歸對比子節(jié)點,當子節(jié)點是列表時,通過key和props來判斷。若key一致,則進行更新,若key不一致,就銷毀重建
當點擊按鈕時,setInitMap([1,2,3,4])會造成渲染,渲染時會生成新的虛擬dom,但此時獲取到的span元素是之前的元素(因為setInitMap是異步執(zhí)行的),所以新舊dom會做對比
在initMap.map((it,index) => <div key={Math.random()}><span>color</span></div>)這段代碼中
這里的div是列表,對比第四條diff規(guī)則,react會根據(jù)key來判斷是否更新真實dom。key= {Math.random()},新舊dom的值不一致,就會重新生成div。而我們是給更新之前的元素加了紅色的樣式,所以重新創(chuàng)建的元素上不會有這個樣式,效果如下
上面我們分析的結(jié)果是,因為key的變化,導(dǎo)致div元素在render的時候會重新生成。那如果key在render前后保持不變呢?例如,將key改為index
問題: 這段代碼在button點擊之后,span的顏色會變嗎?
return ( <div className="App" id="app"> <Spin spinning={spin}></Spin> { initMap.map((it,index) => <div key={index}><span>color</span></div>) } <button onClick={() => handleClick()}></button> </div> );
答案:會
分析: 因為在render前后,index不變,所以div不會重新生成,接著對比span元素,span元素在render前后,屬性變化,因此react只會為span元素應(yīng)用新的屬性,但是他們指向的還是之前的元素
在這個例子中,通過將key設(shè)置成index,span的顏色有了變化,但是在使用key時,React官網(wǎng)不推薦使用index
改造一下上面的代碼
const [initMap, setInitMap] = useState([1,2,3,4]); const handleClick = () => { setInitMap([3,2,1,4]) } return ( <div className="App" id="app"> { initMap.map((it,index) => <div key={index}><input type="radio" />{it}</div>) } <button onClick={() => handleClick()}>點擊</button> </div> ); }
在初始化的時候選中值為3的按鈕
點擊按鈕
我們預(yù)期的效果是,選中的依舊是值為3的按鈕,但此時變成了值為1的按鈕
分析:
setState之后會導(dǎo)致render
div的index不變,所以div不會重新生成,input不受state和props控制,因此元素的狀態(tài)不變
所以變化的只有受state影響的it
測試一:
{ initMap.map((it) => <div key={it}><input type="radio" />{it}</div>) }
初始化的時候選中第三個按鈕
點擊按鈕
思考一下,將key設(shè)置為Math.random(),會有什么效果?按鈕的狀態(tài)會保留嗎?
點擊前:
點擊后:
通過上面的例子,我們大概可以理解React中key的作用了,下面的內(nèi)容是對React知識點的一些擴展
擴展內(nèi)容: 文章開始的代碼還涉及React兩個其他知識點,一個是提到過的React渲染條件,一個是對真實dom的操作;
擴展一: React渲染條件
import './App.css'; import React, { useState } from 'react'; function App() { const [initMap, setInitMap] = useState([1,2,3,4]); const [spin, setSpin] = useState(false); const handleClick = () => { setSpin(true); //變化部分 var spanEle = document.getElementsByTagName('span'); Array.from(spanEle).map(it => it.style.color = 'red') setSpin(false); //變化部分 } return ( <div className="App" id="app"> <Spin spinning={spin}></Spin> { initMap.map((it,index) => <div key={Math.random()}><span>{it}</span></div>) } <button onClick={() => handleClick()}></button> </div> ); } export default App;
測試結(jié)果如下 點擊前:
點擊后:
在這段代碼中,div的key仍然使用的是Math.random(),但initMap的state并沒有改變,所以沒有重新渲染,此時div不會銷毀重建
在React中,虛擬dom的出現(xiàn)是為了減少對真實dom的操作,因為真實的dom元素是一個較復(fù)雜的對象,操作的話計算量比較大。我們上面的代碼中,都是直接操作dom節(jié)點,更改樣式,這樣并不可取。由于React是根據(jù)state和props的變化來渲染頁面,因此通過state來控制頁面渲染比較好
修改后的代碼如下:
function App() { const [initMap, setInitMap] = useState([1,2,3,4]); const [spin, setSpin] = useState(false); const [showColor, setShowColor] = useState(false); const handleClick = () => { setInitMap([3,2,1,4]); setShowColor(true); } return ( <div className="App" id="app"> <Spin spinning={spin}> { initMap.map((it,index) => <div key={Math.random()}><span className={showColor && 'span-color'}>color</span></div>) } </Spin> <button onClick={() => handleClick()}>點擊</button> </div> ); }
此時span是受控組件,可以通過showColor的狀態(tài)控制元素的渲染
點擊前:
點擊后:
使用state控制渲染后,代碼量會變少,同時結(jié)果符合預(yù)期
關(guān)于“React中key的作用有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。