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

React?中的列表渲染要加?key的原因分析

 更新時間:2022年07月01日 09:50:39   作者:前端西瓜哥  
這篇文章主要介紹了React?中的列表渲染為什么要加?key,在?React?中我們經(jīng)常需要渲染列表,比如展示好友列表,文中給大家介紹了列表渲染不提供?key?會如何,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友一起看看吧

在 React 中我們經(jīng)常需要渲染列表,比如展示好友列表。

常用寫法是用 Arrary.prototype.map 方法,將數(shù)組形式的數(shù)據(jù)映射為 JSX.Element 數(shù)組,并嵌入到組件要返回的 JSX.Element 中,如下:

function FriendList() {
  const [items, setItems] = useState(['腳本之家', '小明', '張三']);
  return (
    <ul>
      {items.map((item) => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

你需要給每個項提供 key 屬性作為標(biāo)識,以區(qū)分不同的項。如果你不加 key,React 會警告你:

Warning: Each child in a list should have a unique "key" prop.

為什么需要 key?

在回答這個問題之前,我們先簡單了解一下 React 的 DOM Diff 算法原理。

React 會在狀態(tài)發(fā)生變化時,對真實(shí) DOM 樹按需批量更新,產(chǎn)生新的 UI。

為此底層做的工作是:將新舊兩棵虛擬 DOM 樹進(jìn)行 diff 對比,計算出 patch 補(bǔ)丁,打到真實(shí) DOM 樹上。

為了高效,React 的 diff 算法做了限制:

  • 只做同層級的節(jié)點(diǎn)對比,不跨層級比較。
  • 如果元素的類型不同(如從 p 變成 div),那它們就是不相同的,會銷毀整個舊子樹,并調(diào)用其下組件的卸載鉤子,然后再創(chuàng)建全新的樹,相當(dāng)消耗性能。
  • 如果類型相同,會進(jìn)行打補(bǔ)丁操作(如更新 className 和標(biāo)簽下的文本內(nèi)容)。

但這樣做會有一個問題,如果同級的多節(jié)點(diǎn)  只是位置發(fā)生了變化 ,但因為相同索引位置對不上,又發(fā)現(xiàn)不能復(fù)用,就要銷毀一棵樹并創(chuàng)建一棵新樹,實(shí)在是太過于低效了。

于是 React 給開發(fā)者提供 key 來標(biāo)記節(jié)點(diǎn),來優(yōu)化 React diff 算法,告知 React 某個節(jié)點(diǎn)其實(shí)沒有被移除或不能被原地復(fù)用,只是換了位置而已,讓 React 更新一下位置。

列表渲染不提供 key 會怎樣?

不提供 key,React 就無法確定某個節(jié)點(diǎn)是否移動了。

React 就只會對比相同位置的兩個節(jié)點(diǎn),如果它們類型相同(比如都是 li 元素),就會對比 props 的不同,進(jìn)行 props 的打補(bǔ)丁。

?因為 列表渲染通常都是相同的類型,所以位置變動時,多半是會觸發(fā)節(jié)點(diǎn)原地復(fù)用效果,倒是不用擔(dān)心樹的銷毀重建發(fā)生。

原地復(fù)用在不提供 key 的時候有時候也是能正確渲染的。

除了一種情況,就是 這個節(jié)點(diǎn)有自己的內(nèi)部狀態(tài),最經(jīng)典的莫過于輸入框。

function FriendList() {
  const [items, setItems] = useState(['腳本之家', '小明', '張三']);
  const swap = () => {
    [items[0], items[1]] = [items[1], items[0]];
    setItems([...items]);
  };
  return (
    <div>
      <ul>
        {items.map((item) => (
          <li>{item}<input /></li>
        ))}
      </ul>
      <button onClick={() => { swap(); }}>
        交換
      </button>
    </div>
  );
}

我們給第一和第二個輸入框輸入內(nèi)容。

再點(diǎn)擊 “交換” 按鈕,交換數(shù)組第一和第二個元素位置。

然后我們看到 input 前面的文字正確交換了,但是輸入框里的內(nèi)容卻沒有交換。

?原因是 React 做了原地復(fù)用,而 input 沒有傳 props,不需要打 props 補(bǔ)丁,保持了原樣。

這個問題怎么解決?加 key。讓 React 知道你的節(jié)點(diǎn)需要移動,你得這樣寫:?

items.map((item) => (
  <li key={item}>{item}<input /></li>
))

不使用 key 的另一個缺點(diǎn)是:因為原地復(fù)用會使傳入的 props 發(fā)生變化,導(dǎo)致不能利用好 React.memo 的組件緩存能力。

列表渲染的 key 用數(shù)組索引會怎樣?

效果和不使用 key 相同,依舊是新舊節(jié)點(diǎn)的相同索引位置對比,但是控制臺不會打印警告。

應(yīng)該用什么值作為 key?

對于節(jié)點(diǎn),你需要用一個唯一的 id 賦值給 key,通常會是數(shù)組的 id,比如后端返回的好友列表的好友 id。

const [items, setItems] = useState([
  { id: 5, name: '腳本之家' },
  { id: 9, name: '小明' },
  { id: 87, name: '張三' },
  { id: 91, name: '腳本之家' }
]);
const list = items.map((item) => (
  <li key={item.id}>{item.name}</li>
));

如果后端沒有返回 id,你可以自己手動用一個 id 生成器補(bǔ)上一個 id,雖然不太優(yōu)雅就是了。比如:

const items = ['腳本之家', '張三'];
const genId = (() => {
  let i = 0;
  return () => {
    return i++;
  }
})();
const itemsWithId = items.map(item => ({ id: genId(), val: item }));
// [{id: 0, val: '腳本之家'}, {id: 1, val: '張三'}]

對了,這個 key 只需要在同一個層級的節(jié)點(diǎn)唯一即可,不要求所有層級的 key 都是唯一的。

另外,如果你確保你的列表渲染后直到被銷毀,不會有位置上的變化,可以使用數(shù)組索引為 key。

結(jié)尾

對于列表的渲染,我們有必要提供 key,來對節(jié)點(diǎn)進(jìn)行區(qū)分,React 的 DOM Diff 算法會基于 key 進(jìn)行節(jié)點(diǎn)位置的調(diào)整,確保一些涉及到內(nèi)部狀態(tài)的節(jié)點(diǎn)的渲染狀態(tài)。

通常來說,key 值應(yīng)該是唯一的,通常來自后端返回的數(shù)據(jù)。在你確認(rèn)列表不會發(fā)生位置變更時,可以使用數(shù)組索引作為 key,以去掉惱人的警告提示。

有一個點(diǎn)需要說明的是,key 并不是列表渲染的專屬,普通的節(jié)點(diǎn)也可以用 key。

到此這篇關(guān)于React 中的列表渲染為什么要加 key的文章就介紹到這了,更多相關(guān)React列表渲染 key內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React+ResizeObserver實(shí)現(xiàn)自適應(yīng)ECharts圖表

    React+ResizeObserver實(shí)現(xiàn)自適應(yīng)ECharts圖表

    ResizeObserver是JavaScript的一個API,用于監(jiān)測元素的大小變化,本文主要為大家介紹了React如何利用ResizeObserver實(shí)現(xiàn)自適應(yīng)ECharts圖表,需要的可以參考下
    2024-01-01
  • React?TypeScript?應(yīng)用中便捷使用Redux?Toolkit方法詳解

    React?TypeScript?應(yīng)用中便捷使用Redux?Toolkit方法詳解

    這篇文章主要為大家介紹了React?TypeScript?應(yīng)用中便捷使用Redux?Toolkit方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • React里的Fragment標(biāo)簽的具體使用

    React里的Fragment標(biāo)簽的具體使用

    本文主要介紹了React里的Fragment標(biāo)簽的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • React中用@符號編寫文件路徑實(shí)現(xiàn)方法介紹

    React中用@符號編寫文件路徑實(shí)現(xiàn)方法介紹

    在Vue中,我們導(dǎo)入文件時,文件路徑中可以使用@符號指代src目錄,極大的簡化了我們對路徑的書寫。但是react中,要想實(shí)現(xiàn)這種方式書寫文件路徑,需要寫配置文件來實(shí)現(xiàn)
    2022-09-09
  • React項目build打包頁面空白的解決方案

    React項目build打包頁面空白的解決方案

    React項目執(zhí)行build命令后,在本地服務(wù)器打開頁面是空白的,本文主要介紹了React項目build打包頁面空白的解決方案,感興趣的可以了解一下
    2023-08-08
  • React初始化渲染過程示例詳解

    React初始化渲染過程示例詳解

    這篇文章主要為大家介紹了React初始化渲染過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • React函數(shù)式組件與類組件的不同你知道嗎

    React函數(shù)式組件與類組件的不同你知道嗎

    這篇文章主要為大家詳細(xì)介紹了React函數(shù)式組件與類組件的不同,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • react項目使用redux初始化方式

    react項目使用redux初始化方式

    這篇文章主要介紹了react項目使用redux初始化方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • react導(dǎo)出excel文件的四種方式

    react導(dǎo)出excel文件的四種方式

    本文主要介紹了react導(dǎo)出excel文件的四種方式,主要包括原生js導(dǎo)出,使用?js-export-excel,使用xlsx導(dǎo)出, 使用react-html-table-to-excel,感興趣的可以了解一下
    2023-11-11
  • 每天學(xué)習(xí)一個hooks?useMount

    每天學(xué)習(xí)一個hooks?useMount

    這篇文章主要為大家介紹了每天學(xué)習(xí)一個hooks?useMount,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05

最新評論