pcwu's TIL Notes


[React] List key 的使用

Intro

在 React 中有用到 Array.prototype.map() 等方法產生子元件時,例如像是印出 Todo 清單,會被要求要使用 key,如果沒使用的話,會出現 warning:

Warning: Each child in an array or iterator should have a unique "key" prop.

看一下官方怎麼說:

Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:

也就是說 key 是拿來分辨每個元件的依據,所以必須給予一個唯一的鍵值,好供 React 分辨。

理由相當簡單,DOM 的操作相當昂貴,最好能省則省,所以透過鍵值來判斷比對,可以大幅提高效能。

Compare

例如如果沒有 key 的話,有一個 Todo List 原本有 5 個項目:

todos = [
  { text: "Buy Milk", completed: false },
  { text: "Buy Book", completed: false },
  { text: "Go Gym", completed: true },
  { text: "Have fun", completed: false },
  { text: "Ask her out", completed: false },
];

如果從最開頭插入一個新項目,則整個 List 原本每個位置上的值都變了,React 會全部打掉重來:

todos = [
  { text: "Pay Bill", completed: false }, // New Item, was "buy Milk here".
  { text: "Buy Milk", completed: false }, // Was "Buy Book" here.
  { text: "Buy Book", completed: false }, // ...
  { text: "Go Gym", completed: true },  // ...
  { text: "Have fun", completed: false }, // ...
  { text: "Ask her out", completed: false }, // New Item for React.
];

但如果給予 key 的話,則可以很好地判斷只有一個項目改變,大幅減少 DOM 的操作。

Why Not Use Index?

千萬不要拿 List index 來當 key,這對效能沒有任何幫助。

繼續上面的例子,如果拿 index 來當 key 的話:

todos = [
  { text: "Buy Milk", completed: false }, //index 0
  { text: "Buy Book", completed: false }, //index 1
  { text: "Go Gym", completed: true }, //index 2
  { text: "Have fun", completed: false }, //index 3
  { text: "Ask her out", completed: false }, //index 4
];

還是一樣全毀了,對 React 來說,所有 key 對應的內容都全換掉了,還是得大量操作 DOM:

todos = [
  { text: "Pay Bill", completed: false }, // index 0, was "buy Milk here".
  { text: "Buy Milk", completed: false }, // index 1, was "Buy Book" here.
  { text: "Buy Book", completed: false }, // ...
  { text: "Go Gym", completed: true },  // ...
  { text: "Have fun", completed: false }, // ...
  { text: "Ask her out", completed: false }, // New Item for React.
];

所以 key 必須使用一個會跟著內容走的東西,例如最好的例子就是資料庫該筆資料的 id

這篇文章 有提到如果使用 indexkey 其實不止效能問題,有時候甚至會出錯,有興趣可以看看。

Reference