React 為何不用index當map的key值?

錢端工程師JW (Jinwei)
LT Lab
Published in
6 min readJul 24, 2019

為何不要用Map的index來當作react的key呢?

當我們在寫react時,免不了使用map,用了map如果沒有加key值就會報以下的warning!

當沒加key值時,在console中的warning

而最簡單不報warning的方式就是直接把map出來的key值加上map的index參數。雖然不報warning,但是在效能中卻是一大損傷!因此非常不建議使用index來當key值

主要原因:react會因為key值改變而重新render

react中key的用途:幫助render出的component有效的辨別是否有被刪減、新增、修改!

證明如下:

  1. 在父層建立一個array並將此陣列map出來並傳到子組件裡面。
  2. 子組件用PureComponent: 用來辨別組件是否有重新render。

有重新渲染的話會被console出來。

3. 證明方式:利用slice, push, unshift等方法改變陣列內容。

程式碼

A. State部分

父組件 /index.js state = {data: [    { text: "name", value: "Jinwei" },    { text: "gender", value: "male" },    { text: "location", value: "Taiwan" },    { text: "hometown", value: "Nantou" }   ]};

B. function部分&測試邏輯

主要有三個function

  • removeFirst(): 把原本的data陣列第一個值刪掉
  • addIntoFirst(): 把新的值unshift到data陣列的第一項
  • addIntoLast(): 把新的值push到data陣列的第一項

removeFirst() {
const newData = this.state.data.slice(1); this.setState({ data: newData });}addIntoFirst() { const { data } = this.state; data.unshift(
{text: `index${Math.random()}`,
value: Math.floor(Math.random() * 10)}
);
this.setState({ data: data })}
addIntoLast() { const { data } = this.state; data.push(
{text: `index${Math.random()}`,
value: Math.floor(Math.random() * 10)}
);
this.setState({ data: data })}

C.children組件(ChildList.js)

D. render 部分(index.js)

把畫面呈現出來

主要依據不同的button可以測試不同狀況下react是否做多餘的組件渲染

PS. 測試時可先把其他<h1>部分先註解,可以看得比較清楚!

畫面呈現(當該項component有被render時,就會被console出來)

測試邏輯

如果用index來當作key值的話,則三種function測試結果如下

原本State
state = {
data: [
{text:"name",value:"Jinwei"},
{text:"gender",value:"male"}, {text:"location",value:"TW"}, {text:"hometown",value:"NT"}]};
  1. removeFirst()
Before                               After  
key=0 {text:"name",value:"Jinwei"} {text:"gender",value:"male"}
key=1 {text:"gender",value:"male"} {text:"location",value:"TW"}
key=2 {text:"location",value:"TW"} {text:"hometown",value:"NT"}
key=3 {text:"hometown",value:"NT"}

因此react會覺得四個順序不一樣所以會重新render!

  • ↓執行removeFirst()之前的狀況: 畫面第一次render所以都會有console
  • ↓執行removeFirst()之後後面三項會被重新render

比較: 不使用index,使用獨特的id

會發現console是空的,組件完全沒有被render!

同理: 可嘗試addIntoFirst()與addIntoLast()試試看(點最下方程式碼範例)

結論

  1. 用map的index來當key值只要會改變整體的順序,組件就會重新render
  • 如果用push加在array後面基本上不會重新render(沒改變順序)

2. 建議如果有能當作key值的資料,就不要用index值,積少成多,整體效能會受影響。但如果沒有其他值能當作key那還是只能用index當key值。

Reference:

  1. React Lists and Keys

2. HiSkio React教學

React Key範例程式碼:

--

--

錢端工程師JW (Jinwei)
LT Lab
Editor for

轉職前端變有錢! 從非本科系到外商前端工程師,熱愛分享學習知識及生活啟發。 關於我:https://www.instagram.com/richfront.jw 聯絡信箱: richfront.jw@gmail.com