「key」 props in React component

key props

  • 每一個 React component 在實例化時,都可以綁定一個 key 給它
1
2
3
...
<Component key={'myKey'} />
...
  • key 即 Virtual DOM 的 身分證
    • 當 VDOM Tree 中某個 node 上一次與這一次的 key 值不同, 即視為 不同 node
    • 因此可利用變化 key 的技巧, 來強迫 Component remount

Use Array's index as key v.s. Use uniqle uuid as key

假設有一個 Array

1
const array = ['apple', 'banana', 'grape'];

將這個 array 的 value 透過 Item Component 呈現 (使用 ‘label’ 這個 props 灌下去)

1
2
3
4
5
6
7
class App extends React.PureComponents {
render() {
return (
{ array.map((elem, index) => (<Item key={index or elem} label={elem,} />)) }
)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Item extends React.PureComponent {
label = null;
componentWillMount() {
console.log(`${this.props.label} mount!`);
this.label = this.props.label;
}
componentWillUnmount() {
console.log(`${this.props.label} un mount!`);
}
render() {
console.log(`${this.props.label} render!`);
return (
<div>
{this.props.label} --- {this.label}
</div>
);
}
}

以插入元素(‘peach’)到 Array 的頭為例,陣列變成

1
['peach', 'apple', 'banana', 'grape']
  • index as key

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 螢幕上呈現
    peach --- apple
    apple --- banana
    banana --- grape
    grape --- grape

    // console .
    peach render!
    apple render!
    banana render!
    grape mount!
    grape render!
    • 前後的 key 比較

      1
      2
      3
      Old: 0 - 1 - 2
      | | |
      New: 0 - 1 - 2 - 3
    • 舊的 React DOM 有 key 0, 1, 2 這三個 node, 而新的 React DOM 新增了一個 key 為 3 的 node .

    • React 判斷 0, 1, 2 這三個 node 更動了 'label' props (e.g. 0 這個 node 的 label 從 ‘apple’ 變成 ‘peach’), 因此只 re-render, 也就是他們其實都維持原本的 instance, 沒有經過 unmount => 一開始在componentWillMount() 設定的 this.label 維持不變 .
    • key 為 3 為新的 node, 建立新的 instance => mount
  • label as key (uniqle key)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 螢幕上呈現
    peach --- peach
    apple --- apple
    banana --- banana
    grape --- grape

    // console .
    peach mount!
    peach render!
    • 前後的 key 比較

      1
      2
      3
      Old: apple - banana - grape
      \ \ \
      New: peach - apple - banana - grape
    • 以 apple, banana, grape 為 key 的 instance, 因為沒有任何新的 props 傳下去, 不會 re-render 也不會 unmount

    • 以 peach 為 key 的 instance 是新的 => mount
  • Sample code: React key

Use index as key 可能 會遇到的問題

Performance issue

  • 不必要的 re-render

結果呈現不如預期

  • React 判斷前後為同一個 instance, 但實際上並非如此