iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
自我挑戰組

程式碼 AI 寫,我負責看懂:30 天拆解 React × TypeScript系列 第 8

Day 08|v-for 不見了:React 為什麼一直在 map()?

  • 分享至 

  • xImage
  •  

React 沒有 v-for?

過去在使用 Vue 的專案中,會看到利用 v-for 顯示待辦事項清單:

<!-- TodoList.vue -->
<TodoItem
  v-for="todo in todos"
  :key="todo.id"
  :todo="todo"
/>

v-for="todo in todos" 會逐一取得 todos 裡的資料,並為每一筆資料建立一個 TodoItem Component。

啊再看到另一邊 React 專案,看到的不是 v-for,而是:

// TodoList.tsx
{todos.map((todo) => (
  <TodoItem
    key={todo.id}
    todo={todo}
    onToggle={onToggle}
    onDelete={onDelete}
  />
))}

這裡的 map() 不是 React 提供的特殊語法,而是 JavaScript Array 本身就有的方法。
React 沒有另外設計一個清單指令,而是直接使用 JavaScript 的 map(),將陣列中的每一筆資料轉換成 JSX。

JavaScript 的 map() 是什麼?

map() 會逐一讀取陣列裡的每個項目,並根據回傳的內容建立一個新陣列。
例如:

const todos = ['學習 JSX', '認識 Props', '理解 map']

const listItems = todos.map((todo) => (
  <li key={todo}>{todo}</li>
))

map() 會執行三次,每次的 todo 分別代表陣列中的一筆資料,最後產生三個 <li>

<li>學習 JSX</li>
<li>認識 Props</li>
<li>理解 map</li>

React 可以顯示包含多個 JSX Element 的陣列,因此可以將結果放進 <ul>

return <ul>{listItems}</ul>

也可以直接將 map() 寫進 JSX:

return (
  <ul>
    {todos.map((todo) => (
      <li key={todo}>{todo}</li>
    ))}
  </ul>
)

所以在 React 中,map() 的工作可以先理解成:

將陣列中的每一筆資料轉換成一個 JSX Element。

拆解專案中的 map()

回到目前 Todo List 專案中的程式碼,這裡的 todos 放的不是單純的字串,而是像 { id, text, completed } 這樣的 Todo 物件:

<ul className="todo-list">
  {todos.map((todo) => (
    <TodoItem
      key={todo.id}
      todo={todo}
      onToggle={onToggle}
      onDelete={onDelete}
    />
  ))}
</ul>

這段程式碼的執行方式是:

  1. 取得 todos 陣列。
  2. 使用 map() 逐一讀取每筆資料。
  3. 使用 todo 代表目前這筆待辦事項。
  4. 每一筆 todo 都回傳一個 TodoItem。
  5. React 將產生的 TodoItem 顯示在 <ul> 裡。

其中:

todo={todo}

表示將目前這筆 todo 透過 Props 傳給 TodoItem
假設 todos 有三筆資料,map() 就會產生三個 TodoItem Component。
因此,整段程式碼可以理解成:

todos 裡的每一筆資料轉換成一個 TodoItem

map() 真的等於 v-for 嗎?

比較兩個專案的寫法:

<!-- Vue -->
<TodoItem
  v-for="todo in todos"
  :key="todo.id"
  :todo="todo"
/>
// React
{todos.map((todo) => (
  <TodoItem
    key={todo.id}
    todo={todo}
  />
))}

兩者達成的結果很接近,都是逐一取得陣列資料並建立 Component。
只不過 map() 並不是 React 版本的 v-for,因為 map() 原本就是 JavaScript 的陣列方法。React 只是使用 map() 回傳的 JSX 陣列來顯示清單。

比較準確的理解是:
Vue 使用 v-for 處理清單;React 直接使用 JavaScript 的 map() 將陣列轉換成 JSX 清單。

為什麼需要 key

使用 map() 產生清單時,每一個項目都需要一個 key

key={todo.id}

key 可以幫助 React 辨認每個 Component 對應到陣列中的哪一筆資料。
當清單中的資料被新增、刪除或重新排序時,React 可以透過 key 判斷哪些項目發生變化,並正確更新畫面。

適合的 key 必須:

  • 在同一組清單中保持唯一
  • 不會在每次 Render 時改變
  • 最好使用資料本身穩定的 ID

目前專案中的每一筆 Todo 都有自己的 id

const newTodo: Todo = {
  id: Date.now(),
  text,
  completed: false,
}

因此可以使用:

key={todo.id}

不建議在 Render 時隨機產生 key

key={Math.random()}

因為每次 Render 都會得到不同的值,React 便無法確認這次與上次的項目是不是同一筆資料。
如果資料本身有穩定的 id,也不應優先使用陣列索引:

key={index}

因為清單被新增、刪除或重新排序時,索引可能跟著改變。

另外,key 是 React 使用的特殊屬性,不會像一般 Props 一樣傳給 TodoItem
React 官方文件也建議使用資料中穩定且唯一的 ID 作為 key
React 官方文件:Rendering 列表

今日回顧

  • React 沒有 v-for 指令,而是直接使用 JavaScript 的 map() 把陣列轉換成 JSX
  • map() 會逐一處理陣列中的資料,並根據每次回傳的內容建立新陣列
  • 使用 map() 產生清單時,每個項目都需要 key
  • key 應該使用資料中穩定且唯一的 ID
  • key 是 React 的特殊屬性,不會成為一般 Props

到目前為止 React 給我的感覺仍然比較像是在寫 JavaScript。

今天先安餒,既然寫了 v-for ,那下一篇沒意外就是跟 v-if 相關了


上一篇
Day 07|Vue 有 Props,React 也有 Props:真的一樣嗎?
系列文
程式碼 AI 寫,我負責看懂:30 天拆解 React × TypeScript8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言