iT邦幫忙

0

筆記|React - 8 - 渲染 List

Kim 2023-05-10 16:29:30530 瀏覽
  • 分享至 

  • xImage
  •  

☁️ 開場

開發時常會遇到要渲染一筆陣列資料,而這些資料呈現的方式雷同,使用 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)

三、補充:map 中 return 寫法(以下情境皆為使用 arrow function)

  • 在沒有 {} 的情況下不用寫 return,為 concise body
    • 這時的 JSX 也可以換行寫
    const listItems = chemists.map(person =>
          <li>...</li> // Implicit return!
    );
    
  • 在有 {} 的情況下要寫 return,因為會形成一個 block body
    • return 完要馬上接 JSX 或單一個 (,不能換行才接,不然沒東西回傳
    const listItems = chemists.map(person => { // Curly brace
      return <li>...</li>;
    });
    
    const listItems = chemists.map(person => { // Curly brace
     return (
         <li>...</li>;
     )
    });
    

🗝 fix error message,渲染 List 的關鍵 —— key!

總算要來處理 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?

適合的 Key 才能讓 React 正確的更新 DOM tree!

🔸 原則

  1. 唯一性:在同層元素中,key 要是唯一的!在不同的 JSX nodes 陣列用到相同的 key 是沒關係的
  2. 不變性:Key 必須要是不變的,不要在 render 的過程中產生 key,ex. key={Math.random()},這讓 key 在每次 render 間都不同,於是 React 就會重製那些不需要重製的 DOM,導致效能變慢,也可能因此遺失一些使用者在那些 list items 所輸入的資料

🔸 實務情境中的選擇,可以分成兩種資料

  1. 如果資料是從 Database 來的,可以直接使用 Database 產生的 id 當作 key,這些 id 就符合原則
  2. 如果資料是在 local 創建的,可以在新增資料時用 crypto.randomUUID() 或是 uuid 套件為資料生成 id

🔸 可以用 index 當 key 嗎?

可以,但不建議,事實上當我們沒有設定 key 的時候,React 底層就是這麼做。不建議的原因是因為 index 會隨著陣列的順序調動或增減而產生變動,就違反了不變性。

若想感受使用 index 所造成的功能異常,可以搶先看後面官方文件所提供 codebox

四、延伸思考:如果 map 要同時回傳多個同階層的 JSX 該怎麼寫?

要回傳多個同階層的 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>
);

// ...

五、觀念補充

  1. 元件不會接收到 key 這個 prop 值,key 只是 React 自己使用的,如果真的要在元件中用到 id 值,就要額外放入一個 prop, ex. <Profile key={id} userId={id} />.
  2. 如果 map 回傳的是另一個元件,一樣要加 key <Recipe key={id} />,而這個 key 是綁在「Recipe」上,並不是「Recipe 元件裡的第一層 element」!(來自 Challenge3

💃🏻 總結

本篇官方文件的 Recap,只是說明學了什麼,並沒有做統整,以下是個人的總結

  • 使用 map 創造 JSX nodes 陣列,都要擺入 key prop
  • 適合的 key 要具有唯一性、不變性,建議將 key 直接存於資料中,然後用 map 時直接從資料抓取

以上,有任何想法或文內有誤、不清楚歡迎提出,謝謝大家 🙏🏻
.
筆者小記:key 就是 rendering list 的 key ! (*•̀ㅂ•́)و


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言