啰嗦啰嗦React/Vue里key這個(gè)東東

前言:最近面試經(jīng)常聊到key的概念,一個(gè)非常常見的知識(shí)點(diǎn),但還是遇到了一部分并不理想的情況。所以我想再啰嗦啰嗦,交流分享一下我的理解和認(rèn)識(shí)。


key這個(gè)概念,無(wú)論是React還是Vue,寫過(guò)的同學(xué),應(yīng)該沒有不知道的。對(duì)于key的理解,大部分人都描述的相差無(wú)二,基本都是在渲染數(shù)組列表的場(chǎng)景,條目項(xiàng)在添加、刪除或調(diào)整順序時(shí),前后便于對(duì)應(yīng)起來(lái),提供diff以及渲染性能。

下面就以React為例嘮一嘮,先參考一下官網(wǎng)文檔的說(shuō)明:

“key” 是在創(chuàng)建元素?cái)?shù)組時(shí),需要用到的一個(gè)特殊字符串屬性。key 幫助 React 識(shí)別出被修改、添加或刪除的 item。應(yīng)當(dāng)給數(shù)組內(nèi)的每個(gè)元素都設(shè)定 key,以使元素具有固定身份標(biāo)識(shí)。

只需要保證,在同一個(gè)數(shù)組中的兄弟元素之間的 key 是唯一的。

不要將 Math.random() 之類的值傳遞給 key。重要的是,在前后兩次渲染之間的 key 要具有“固定身份標(biāo)識(shí)”的特點(diǎn),以便 React 可以在添加、刪除或重新排序 item 時(shí),前后對(duì)應(yīng)起來(lái)。理想情況下,key 應(yīng)該從數(shù)據(jù)中獲取,對(duì)應(yīng)著唯一且固定的標(biāo)識(shí)符,例如 post.id。

這個(gè)說(shuō)道在創(chuàng)建元素?cái)?shù)組時(shí),因?yàn)檫@一點(diǎn),應(yīng)該有相當(dāng)一部分人就局限于此了。我們多想一想,這里實(shí)際上只是一個(gè)特別有代表性,而且便于理解釋義的一個(gè)場(chǎng)景case。多理解理解上面的解釋,幫助React識(shí)別,使元素具有固定身份標(biāo)識(shí),唯一性,為什么需要這樣呢,達(dá)成這樣的條件,React它是想做什么?從這里我深入想一想,研究一下。

首先 SHOW ME YOUR CODE!

元素?cái)?shù)組的case,個(gè)人認(rèn)為就沒有必要跟大家絮叨了,官網(wǎng)以及網(wǎng)上都能找到很多參考,這里我們拿非數(shù)組場(chǎng)景來(lái)研究一下。

只做核心代碼邏輯展示,上下文省略,需要的自行下去完善。
定義一個(gè)示例組件:CompA.js

import { useEffect, useState } from "react";

export default function CompA({ name }) {
  const [val, setVal] = useState("");
  useEffect(() => {
    console.log(name, "mounted!!!");
  }, []);
  return (
    <div className="App">
      <h2>CompA name: {name}</h2>
      <input
        style={{ width: "200px" }}
        value={val}
        onChange={(ev) => setVal(ev.target.value)}
        placeholder="代表組件內(nèi)部狀態(tài), 初始狀態(tài)"
      />
      {val ? <p>當(dāng)前組件內(nèi)部狀態(tài)變化:val = {val}</p> : null}
    </div>
  );
}

示例展示容器: App.js

import "./styles.css";
import CompA from "./CompA";
import { useState } from "react";

export default function App() {
  const [key, setKey] = useState("");
  const [name, setName] = useState("");
  const [cname, setCname] = useState("default");
  const [ckey, setCkey] = useState("a1");

  return (
    <div className="App">
      <h1>React key</h1>
      <input
        placeholder="請(qǐng)輸入key"
        value={key}
        onChange={(ev) => setKey(ev.target.value)}
      />
      <button onClick={() => setCkey(key)}>修改CompA實(shí)例的key</button>
      <br />
      <input
        placeholder="請(qǐng)輸入name"
        value={name}
        onChange={(ev) => setName(ev.target.value)}
      />
      <button onClick={() => setCname(name)}>修改CompA實(shí)例的props: name</button>
      <CompA key={ckey} name={cname} />
    </div>
  );
}
  1. 運(yùn)行效果,初始狀態(tài)
    運(yùn)行效果,初始狀態(tài)

    控制臺(tái)打印內(nèi)容:
    default CompA mounted!!! 
    
  2. 修改組件狀態(tài),效果如下,ComA組件實(shí)例內(nèi)部狀態(tài)發(fā)生了變化
    修改組件狀態(tài),展示效果

    此時(shí)控制臺(tái)無(wú)新的打印
  3. 改變一下CompA組件的props屬性看看
    修改props,展示效果

    此時(shí)組件CompA實(shí)例一直是沒有變化,還是最初構(gòu)建的實(shí)例對(duì)象,因?yàn)榭刂婆_(tái)依然沒有新的打印。
  4. 現(xiàn)在我們改變一下key,試試看
    修改key,展示效果

    此時(shí)控制打印內(nèi)容: (第一行未#1打印的)
    default CompA mounted!!! 
    porps change CompA mounted!!! 
    

結(jié)果很明了了,#4僅僅是改變了key,props還是name='props change',從打印及執(zhí)行展示效果上來(lái)看,組件重新構(gòu)建實(shí)例化了,props還是原來(lái)的,但因?yàn)橹匦聦?shí)例化,內(nèi)部狀態(tài)沒有了,回到了初始狀態(tài)。這點(diǎn)其實(shí)在我們實(shí)際開發(fā)中很有用的,不僅限于元素?cái)?shù)組。
線上查看:https://codesandbox.io/s/react-key-hwq6y

最終總結(jié)一下

React拿key做什么的呢,再回看官網(wǎng)解釋, 重點(diǎn)我們不要僅關(guān)注元素?cái)?shù)組,而唯一的固定身份標(biāo)識(shí)前后對(duì)應(yīng),這點(diǎn)才是核心。
在我面試的時(shí)候,很多候選人還會(huì)說(shuō)到diff算法,理論上說(shuō)的很多都沒有問(wèn)題,甚至沒有破綻。但是否真正理解了diff算法以及key的概念,對(duì)應(yīng)上實(shí)際case,就有一部分?jǐn)嗑€了。
React根據(jù)key,唯一確定定位對(duì)應(yīng)的組件實(shí)例,通過(guò)key更快速定位,綜上因此就是:

  • key相同,復(fù)用保持原實(shí)例,props或者內(nèi)部state狀態(tài)變化,react只更新組件對(duì)應(yīng)變化的屬性。
  • key不同,銷毀之前的組件實(shí)例,再重新構(gòu)建新的組件實(shí)例。(前提上下文,僅針對(duì)當(dāng)前組件,組件數(shù)組情況可對(duì)比參考官網(wǎng))

技術(shù)最重要的還是應(yīng)用,要靈活應(yīng)用好,首先我們要真正的理解它是怎么運(yùn)行的,進(jìn)而邏輯原理,最終能做到觸類旁通,舉一反三,知其然,知其所以然。

參考

React官網(wǎng)-術(shù)語(yǔ)key


個(gè)人理解整理,歡迎交流,如有錯(cuò)誤之處,還請(qǐng)斧正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、簡(jiǎn)介 1、 Vue.js 是什么 參考網(wǎng)址:https://cn.vuejs.org/v2/guide/ind...
    滿天繁星_28c5閱讀 555評(píng)論 0 1
  • 簡(jiǎn)介 上一節(jié)我們完成了從 0 開始搭建一個(gè)企業(yè)級(jí) React 項(xiàng)目的全部?jī)?nèi)容,項(xiàng)目是有了,但是我們一直都沒有近距離...
    vv_小蟲蟲閱讀 423評(píng)論 0 2
  • vue vue是一套用于構(gòu)建用戶界面的漸進(jìn)式框架(漸進(jìn)式框架的大概意思就是你可以只用我的一部分,而不是用了我這一點(diǎn)...
    BigTooth_3611閱讀 546評(píng)論 0 0
  • 此文項(xiàng)目代碼:https://github.com/bei-yang/I-want-to-be-an-archit...
    LM林慕閱讀 1,656評(píng)論 0 6
  • react有一個(gè)特殊屬性key 應(yīng)用場(chǎng)景根據(jù)數(shù)組動(dòng)態(tài)創(chuàng)造,不確定數(shù)量,順序的子節(jié)點(diǎn)時(shí)使用需要對(duì)某一組件的更新操作強(qiáng)...
    mengxr閱讀 730評(píng)論 0 1

友情鏈接更多精彩內(nèi)容