開發時常會遇到要渲染一筆陣列資料,而這些資料呈現的方式雷同,使用 Array method 可以幫助我們避免撰寫重複的程式碼。接下來會著重介紹 .filter()
、.map()
如何幫我們把一筆陣列資料轉換成一筆陣列元件!
這篇筆記主要整理自:官方文件 Rendering Lists
.map()
⬇️ 目標的 JSX
<ul>
<li>Creola Katherine Johnson: mathematician</li>
<li>Mario José Molina-Pasquel Henríquez: chemist</li>
<li>Mohammad Abdus Salam: physicist</li>
<li>Percy Lavon Julian: chemist</li>
<li>Subrahmanyan Chandrasekhar: astrophysicist</li>
</ul>
⬇️ 作法
export default function() {
// 第一步:有一筆要渲染的陣列資料
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
];
// 第二步:將該陣列 map 成 JSX nodes 陣列
const listItems = people.map(person => <li>{person}</li>);
// 第三步: 把 JSX nodes 陣列放入要渲染的地方
return <ul>{listItems}</ul>;
}
⚠️ 這樣寫確實能成功渲染,但會噴錯!因為還少了關鍵的第四步驟(後續說明,以下為 error message)
.filter()
+.map()
如果遇到有些陣列資料不想要渲染的狀況,就可以先使用 .filter()
把不要的過濾掉,再使用 .map()
⬇️ 以下情境是有一筆關於人物的資料,但我們只要渲染職業是 chemist 的人物
import { getImageUrl } from './utils.js';
const people = [{
id: 0,
name: 'Creola Katherine Johnson',
profession: 'mathematician',
}, {
id: 1,
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
}, {
id: 2,
name: 'Percy Lavon Julian',
profession: 'chemist',
}];
export default function List() {
// 用 filter 過濾取出職業是 chemist 的人物
const chemists = people.filter(person =>
person.profession === 'chemist'
);
// 用 map 將過濾的人物資料轉換為 JSX nodes 的陣列
const listItems = chemists.map(person =>
<li>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
</p>
</li>
);
// 回傳
return <ul>{listItems}</ul>;
}
⚠️ 目前也會噴錯!因為還少了關鍵步驟(後續說明,以下為 error message)
{}
的情況下不用寫 return
,為 concise body
const listItems = chemists.map(person =>
<li>...</li> // Implicit return!
);
{}
的情況下要寫 return
,因為會形成一個 block body
(
,不能換行才接,不然沒東西回傳const listItems = chemists.map(person => { // Curly brace
return <li>...</li>;
});
const listItems = chemists.map(person => { // Curly brace
return (
<li>...</li>;
)
});
總算要來處理 error message 了,它們都是在說需要獨一無二的「key」prop!
文件說到:「JSX elements directly inside a map() call always need keys!」
mapping 時,在第一層 JSX 擺入 key prop !
const listItems = chemists.map(person => {
return <li key={person.id}>...</li>;
});
Keys 會讓 React 知道元件對應到哪個 array item,這對會有順序、數量變動的陣列是重要的,可以幫助 React 判斷這個元件是否有重製的必要,減少不必要的效能浪費。
適合的 Key 才能讓 React 正確的更新 DOM tree!
key={Math.random()}
,這讓 key 在每次 render 間都不同,於是 React 就會重製那些不需要重製的 DOM,導致效能變慢,也可能因此遺失一些使用者在那些 list items 所輸入的資料可以,但不建議,事實上當我們沒有設定 key 的時候,React 底層就是這麼做。不建議的原因是因為 index 會隨著陣列的順序調動或增減而產生變動,就違反了不變性。
若想感受使用 index 所造成的功能異常,可以搶先看後面官方文件所提供 codebox
要回傳多個同階層的 JSX,之前有提到可以使用 <></>
Fragment syntax,但這樣的寫法沒有辦法加上 key prop,要使用另一種比較長、精確的寫法 <Fragment></Fragment>
,這樣寫一樣不會產生 DOM node:
// 記得先引入!
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
// ...
<Profile key={id} userId={id} />
.<Recipe key={id} />
,而這個 key 是綁在「Recipe」上,並不是「Recipe 元件裡的第一層 element」!(來自 Challenge3
本篇官方文件的 Recap,只是說明學了什麼,並沒有做統整,以下是個人的總結
以上,有任何想法或文內有誤、不清楚歡迎提出,謝謝大家 🙏🏻
.
筆者小記:key 就是 rendering list 的 key ! (*•̀ㅂ•́)و