基本介紹
當我們需要渲染多筆資料時,通常會使用陣列的 map()
方法將資料轉換成一系列 React 元件。在這過程中,key
屬性的使用非常重要,原因如下:
為什麼需要 key?
- 唯一標識: key 幫助 React 識別哪些項目發生了變更、增加或刪除。當列表數據更新時,透過
key
,React 可以更有效率地進行重新渲染。 - 效能優化: 正確使用
key
可以降低 DOM 更新的開銷,因為 React 能夠精確地知道哪些元素需要被更新而不是全部重新渲染。
如何選擇 key?
- 穩定且唯一:
key
應該是穩定且唯一的,常見的選擇有資料庫中的id
。如果沒有穩定的id
,則不得不使用索引,但這只適用於靜態列表或不會重新排序的情況。 - 避免使用索引: 在大部分情況下,使用陣列索引作為
key
可能會導致不正確的元件狀態更新,尤其是在列表項目可能增刪或重新排序時。
範例
假設我們有一個待辦事項列表,可以這樣使用key:
function TodoList({ todos }) {我們再演示其它示範:
return (
<ul>
{todos.map(todo => ( // todo 該參數代表陣列中的每一筆資料
// 假設 todo.id 為唯一識別碼
<li key={todo.id}>
{todo.text}
</li>
))}
</ul>
);
}
export default TodoList;
假設你有一個包含數字或字串的陣列,你可以使用 map()
方法將每個項目轉換成一個 JSX 元素:
function NumberList() {
const numbers = [1, 2, 3, 4, 5];
return (
<ul>
{numbers.map(number => (
<li key={number}>{number}</li>
))}
</ul>
);
}
export default NumberList;
- 使用
numbers.map()
將每個數字變為<li>
元素。 - 每個列表項都需要有一個唯一的
key
屬性,這裡使用數字本身作為 key。 - 最後,整個陣列表達式被包在大括號
{}
內,讓 JSX 能夠正確解讀並插入結果。
而通常資料來源並非單純數字,而是一組物件,例如待辦事項清單:
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<h3>{todo.title}</h3>
<p>{todo.description}</p>
</li>
))}
</ul>
);
}
export default TodoList;
// App.jsx
import TodoList from "./TodoList.jsx"
function App() {
// 使用範例
const todosData = [
{ id: 1, title: "學習 React", description: "閱讀官方文件和範例程式碼" },
{ id: 2, title: "實作專案", description: "開始一個小型的 React 專案" },
{ id: 3, title: "進階學習", description: "了解 Hooks 和 Context API" }
];
return (
<>
// 在應用中渲染 TodoList
<TodoList todos={todosData} />
</>
);
}
export default App
- 每個 todo 物件都有獨一無二的 id 作為 key,這有助於 React 追蹤每個項目的狀態。
有時候陣列可能是空的,你可以透過條件渲染來提示使用者:
function MessageList({ messages }) {
if (messages.length === 0) {
return <p>目前沒有訊息</p>;
}
return (
<ul>
{messages.map((message, index) => (
<li key={index}>{message}</li>
))}
</ul>
);
}
陣列的複雜操作
有時候你可能需要對資料進行過濾、排序或其他變換,再渲染到 JSX 中。例如,假設你要只顯示已完成的任務:
function CompletedTodos({ todos }) {
// 過濾出已完成的任務
const completed = todos.filter(todo => todo.completed);
return (
<ul>
{completed.map(todo => (
<li key={todo.id}>
<span style={{ textDecoration: "line-through" }}>{todo.title}</span>
</li>
))}
</ul>
);
}
export default CompletedTodos
// App.jsx
import CompletedTodos from "./CompletedTodos.jsx"
function App() {
// 範例資料
const todosData = [
{ id: 1, title: "學習 React", completed: true },
{ id: 2, title: "寫作業", completed: false },
{ id: 3, title: "看影片", completed: true }
];
return (
<>
// 在應用中渲染 CompletedTodos
<CompletedTodos todos={todosData} />
</>
);
}
export default App
- 先用
filter()
過濾出completed
為 true 的任務。 - 再用
map()
將結果渲染成列表,並可將已完成的任務標記為刪除線。
在一些情況下,你可能需要渲染多層次的資料,例如一個留言串中包含回覆、在TodoList中的每條代辦事項中包含可以刪除的按鈕或其它按鈕。
TodoList項目會在之後的幾章節後再做實現,目前讀者只需要知道相關的邏輯操作。