文章

React 中的列表渲染與key屬性

React 中的列表渲染與 key 屬性

在 React 中,列表渲染是非常常見的需求,通常我們會根據數據生成一組相似的元素。當我們使用 JavaScript 的迴圈來渲染列表時,React 需要能夠唯一識別每個列表項,這時就需要使用 key 屬性來幫助 React 高效地更新和渲染列表。

1. 基本的列表渲染

可以使用 JavaScript 的 map() 方法來迭代數據,並將每個項目轉換成 React 元素。React 會將這些元素渲染為一個列表。

範例:基本列表渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>{number}</li>
  );

  return (
    <ul>{listItems}</ul>
  );
}

export default function App() {
  const numbers = [1, 2, 3, 4, 5];
  return <NumberList numbers={numbers} />;
}

在這個範例中,我們使用 map() 來生成每個數字對應的 li 元素,並在返回的每個 li 元素中使用了 key 屬性。

2. key 屬性的作用

在列表渲染中,key 屬性是非常重要的,它幫助 React 能夠高效地更新和重繪元素。React 使用 key 來識別哪些元素發生了變化、被添加或被移除。key 應該給每個列表中的元素一個唯一的標識符,通常來自數據本身,比如 ID 或唯一的屬性。

範例:key 的重要性

1
2
3
4
5
6
7
8
9
10
11
function NumberList(props) {
  const numbers = props.numbers;

  return (
    <ul>
      {numbers.map((number, index) =>
        <li key={index}>{number}</li>
      )}
    </ul>
  );
}

雖然這個範例看似可以正常工作,但使用 index 作為 key 並不是最好的做法。當列表發生變動時(如重新排序、插入或刪除項目),這種情況下的 key 可能會導致 React 誤判元素更新,從而影響效能和導致 UI 異常。

3. 選擇合適的 key

  • 唯一性:每個 key 在兄弟元素中必須是唯一的。
  • 穩定性key 在不同的渲染中應保持一致,以便 React 能夠正確地識別和更新元素。

當列表的元素具有唯一 ID 時,通常應該使用 ID 作為 key。如果沒有唯一 ID,可以考慮創建或生成一個穩定的唯一值。

範例:使用 ID 作為 key

1
2
3
4
5
6
7
8
9
10
11
12
function TodoList(props) {
  const todos = props.todos;
  return (
    <ul>
      {todos.map((todo) =>
        <li key={todo.id}>
          {todo.text}
        </li>
      )}
    </ul>
  );
}

在這裡,我們使用了 todo.id 作為 key,這是一個唯一且穩定的屬性,因此更適合用於列表渲染。

4. key 並不會傳遞給子組件

需要注意的是,key 並不會自動作為 props 傳遞給子組件。如果子組件需要 key,需要顯式地傳遞。

範例:key 並不會傳遞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function ListItem(props) {
  // 即使父組件有 `key`,子組件中也無法直接訪問它
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()} value={number} />
      )}
    </ul>
  );
}

即使在 NumberList 中給 ListItem 元素提供了 key 屬性,ListItem 本身是無法直接訪問 key 的,key 僅用於 React 內部的追蹤和重繪。

5. 為何不能使用索引作為 key

使用索引作為 key 並不是一個推薦的做法,因為當列表中的元素重新排序或有插入、刪除操作時,索引會改變,這樣會導致 React 誤認為列表項目是新的元素,從而可能造成效能問題或 UI 異常。

範例:不推薦使用索引作為 key

1
2
3
4
5
6
7
8
9
10
11
function NumberList(props) {
  const numbers = props.numbers;

  return (
    <ul>
      {numbers.map((number, index) =>
        <li key={index}>{number}</li>
      )}
    </ul>
  );
}

如果列表內容不會變動或只是靜態展示,使用索引可能沒有太大問題,但如果列表會頻繁變動,應盡量避免使用索引作為 key

6. 為元素生成唯一的 key

當列表的元素沒有明確的唯一 ID 時,可以根據具體情況生成唯一的 key,比如使用 uuid 庫或在範例中創建一個簡單的唯一標識。

範例:使用隨機生成的 key

1
2
3
4
5
6
7
8
9
10
11
12
13
import { v4 as uuidv4 } from 'uuid';

function RandomList(props) {
  const items = props.items;

  return (
    <ul>
      {items.map((item) =>
        <li key={uuidv4()}>{item}</li>
      )}
    </ul>
  );
}

這裡使用 uuid 庫來生成唯一的 key,保證列表中的每個項目都有一個穩定的標識符。


總結

  • 使用 map() 方法來渲染列表,並確保為每個項目提供唯一的 key
  • key 用於幫助 React 追蹤元素的變化,以高效地重新渲染列表。
  • 應盡量避免使用列表的索引作為 key,因為這可能導致渲染錯誤和效能問題。
  • key 並不會作為 props 傳遞給子組件,僅供 React 內部使用。
  • 當列表中的元素沒有唯一的 ID 時,可以考慮使用其他方式生成唯一的 key

透過正確使用 key 屬性,React 可以更高效地管理和渲染複雜的列表,並保持應用的性能和正確性。

本文章以 CC BY 4.0 授權