渲染列表
您經常會希望從資料集合中顯示多個相似的元件。您可以使用 JavaScript 陣列方法 來操作資料陣列。在本頁中,您將使用 filter() 和 map()與 React 一起過濾並將您的資料陣列轉換為元件陣列。
您將學習
- 如何使用 JavaScript 的 從陣列渲染元件
map() - 如何使用 JavaScript 的 僅渲染特定元件
filter() - 何時以及為何使用 React 鍵值
從陣列渲染資料
假設您有一個內容清單。
這些清單項目之間唯一的區別在於它們的內容,也就是它們的資料。在建置介面時,您經常需要使用不同的資料顯示同一個元件的多個實例:從評論清單到個人資料圖片庫。在這些情況下,您可以將資料儲存在 JavaScript 物件和陣列中,並使用map() 和 filter() 等方法從中渲染元件清單。
以下是一個從陣列生成項目清單的簡短範例:
- 將資料移至陣列中:
- 將
people成員映射到一個新的 JSX 節點陣列,listItems:
- 從您的元件中返回
listItems,並將其包裹在<ul>中:
結果如下:
請注意上面的沙盒顯示了一個控制台錯誤:
控制台
警告:清單中的每個子項目都應該有一個唯一的「key」屬性。
您將在本頁後續學習如何修復此錯誤。在此之前,讓我們為您的資料添加一些結構。
過濾陣列項目
這些資料可以進一步結構化。
假設您想要一種方法來僅顯示職業為 'chemist'的人。您可以使用 JavaScript 的filter() 方法來僅返回這些人。此方法接收一個項目陣列,將其通過一個「測試」(一個返回 true 或 false 的函數),並返回一個僅包含通過測試(返回 true)的項目的新陣列。
您只需要 profession 為 'chemist'的項目。對此的「測試」函數看起來像(person) => person.profession === 'chemist'。以下是將其組合在一起的方法:
- 建立一個僅包含「化學家」人員的新陣列,
chemists,方法是對people呼叫filter(),並以person.profession === 'chemist'進行篩選:
- 現在對
chemists進行映射:
- 最後,從你的元件中回傳
listItems:
陷阱
箭頭函式會隱式地回傳緊接在 =>之後的運算式,因此你不需要return陳述式:
然而,如果你的 =>後面跟著一個{ 大括號,你必須明確地寫出return!
包含 => {的箭頭函式被稱為具有「區塊主體」。它們允許你撰寫多行程式碼,但你必須自行撰寫return陳述式。如果你忘記了,將不會回傳任何內容!
使用 key 保持清單項目順序
請注意,上面的所有沙盒都在控制台中顯示了一個錯誤:
控制台
警告:清單中的每個子項目都應該有一個唯一的「key」屬性。
你需要為每個陣列項目提供一個key—— 一個字串或數字,能在該陣列的其他項目中唯一識別它:
注意
直接在 map()呼叫內的 JSX 元素總是需要的 key!
Key 告訴 React 每個元件對應到哪個陣列項目,以便稍後進行匹配。如果你的陣列項目可能移動(例如由於排序)、被插入或被刪除,這就變得非常重要。一個精心選擇的key有助於 React 推斷到底發生了什麼,並對 DOM 樹進行正確的更新。
你應該將 key 包含在你的資料中,而不是動態生成它們:
從哪裡獲取你的key
不同的數據來源提供不同的 key 來源:
- 來自資料庫的數據:如果你的數據來自資料庫,你可以使用資料庫的鍵/ID,它們本質上是唯一的。
- 本地生成的數據:如果你的數據是在本地生成並持久化的(例如筆記應用中的筆記),請使用遞增計數器、crypto.randomUUID()或在創建項目時使用像uuid 這樣的套件。
key 的規則
- key 在同層級元素中必須是唯一的。 但是,在 不同陣列中的 JSX 節點使用相同的 key 是可以的。
- key 不得改變,否則就失去了它們的意義!不要在渲染時生成它們。
為什麼 React 需要 key?
想像一下,如果你桌面上的檔案沒有名稱。相反,你將通過它們的順序來引用它們——第一個檔案、第二個檔案,依此類推。你可能會習慣它,但一旦你刪除一個檔案,就會變得混亂。第二個檔案會變成第一個檔案,第三個檔案會變成第二個檔案,依此類推。
資料夾中的檔案名稱和陣列中的 JSX key 具有相似的目的。它們讓我們能夠在同層級元素中唯一識別一個項目。一個精心選擇的 key 提供的資訊比陣列中的位置更多。即使由於重新排序導致位置 發生變化,key也能讓 React 在其整個生命週期中識別該項目。
陷阱
你可能會想使用項目在陣列中的索引作為其 key。事實上,如果你沒有指定 key,React 就會這麼做。但是,如果插入、刪除項目或陣列被重新排序,你渲染項目的順序會隨時間而改變。使用索引作為 key 通常會導致微妙且令人困惑的錯誤。
同樣地,不要動態生成 key,例如使用key={Math.random()}。這將導致 key 在每次渲染之間永遠無法匹配,從而導致你的所有元件和 DOM 每次都被重新創建。這不僅速度慢,還會丟失列表項目內的任何使用者輸入。相反,請使用基於數據的穩定 ID。
請注意,你的元件不會將 key作為 prop 接收。它僅被 React 本身用作提示。如果你的元件需要一個 ID,你必須將其作為單獨的 prop 傳遞:<Profile key={id} userId={id} />。
總結
在本頁中,你學到了:
- 如何將資料移出元件並放入陣列和物件等資料結構中。
- 如何使用 JavaScript 的
map()來生成一系列相似的元件。 - 如何使用 JavaScript 的
filter()來建立過濾項目的陣列。 - 為何以及如何為集合中的每個元件設定
key,以便即使其位置或資料發生變化,React 也能追蹤每個元件。
Try out some challenges
Challenge 1 of 4:Splitting a list in two #
This example shows a list of all people.
Change it to show two separate lists one after another: Chemists and Everyone Else. Like previously, you can determine whether a person is a chemist by checking if person.profession === 'chemist'.
