---
# System prepended metadata

title: 第二週：React 與元件化
tags: [2023 React 入門攻略工作坊]

---

# 第二週：React 開發環境與元件

- 請務必提醒講師 “錄影”
- 課程最終目標，完成 TodoList
    - 基礎難度：約 2 ~ 3 週課程即可完成
    - 進階難度：約 4 週課程可以完成

- 作品參考：https://works.hexschool.io/#/

### 做作業正確的「心態」

- 試著自己寫，~~用一個番茄鐘解決它~~
- 試著五分鐘後，還是不會寫，就去翻解答、翻別人的
- 照著打也沒關係，但請把註解都打出來
- 如果還有餘力，請重新撰寫一次

## 第二週課綱核心：

- 複習 useState 與介紹 useEffect
- 元件化：
    - 什麼是元件
    - 元件特性：狀態獨立
    - 元件狀態傳遞、元件方法傳遞
    - 什麼時候要建立元件
- 元件生命週期（useState 與 useEffect 運作原理）

## useState 與 useEffect

- useState 複習
- 為什麼要用到 useEffect 與 useEffect 介紹

**複習情境：**

> 範例：AboutUseState (訂單 CRUD)
> 
- 原始的資料列表，包含名稱、金額、id
- 為這筆資料表，新增新的資料
- 刪除資料中的其中一筆
- 當所有資料變動後，將資料金額進行總和


### useEffect - 當狀態改變時，重新執行特定的函式

> 範例：WhyUseEffect
> 
1. 為什麼使用 useEffect
    1. useState 的運作概念：當 useState 觸發時，全元件的資料都會更新一次
        
2. **使用情境：**
    1. 第一次運行時
    2. 監聽特定值

## 元件

### 1. 元件示範

將以下畫面轉成元件

https://getbootstrap.com/docs/5.3/examples/album/

> 新手那麼怕元件，該怎麼辦？
那就不要急著面對它
> 

### 2. 元件狀態、方法管理

> 延伸閱讀：React 中的 `is missing in props validation` 參考[解決方案](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prop-types.md)*。
如果是新手，會建議先略過*
> 

**Props：**

- 傳入值的方法
- Props：前內後外

**轉換秘訣 → 「秘傳」**

1. **先解決版型問題**：複製片段 JSX 程式碼，並建立新檔案儲存
2. **匯入版型元件**：import 該元件，並替換該區塊
3. **最後解決邏輯**：如果該狀態、方法外層也用不到，可以放到內層元件；反之，其餘使用 Props 的方式由外向內傳入

### 3. 什麼時候建立元件

**大原則**

- 程式碼太長的時候
- 當區塊可以重複利用時
- 邏輯特殊，與當前元件差異過大時

## 作業

餐點管理工具

- Level 1：**直接參考解答**，至少製作三個元件（可選擇：左側餐點列表單一品項、單一 <tr>、下方的訂單摘要），要會動
- Level 2：**參考解答**製作菜單工具，可加入購物車並產出結果
    - 挑戰中**省略：刪除、調整數量的功能**
    - 一樣需要至少製作三個元件
- Level 3（挑戰）：**不參考解答**製作菜單工具，可加入購物車並產出結果
    - 不省略任何功能
    - 重複品項無法重複加入，僅會增加數量 1
    - 至少製作三個元件
    - 客製化版型

解答連結：
- 執行範例：https://www.casper.tw/react-2023-homework/#/week2
- 原始碼：https://github.com/Wcc723/react-2023-homework/blob/main/src/pages/Week2.jsx
- 作業繳交連結：https://rpg.hexschool.com/training/37/show?embedhm=CqlyVMtBQhuN5dCYWNcBCA
    
作業使用者故事：

1. 點餐人員可以將左側的品項加入購物車
2. 點餐人員，可以刪除、調整購物車品項數量（Level 2 可不做）
3. 點餐人員可加入備註
4. 點餐人員可以建立訂單

```html
<div id="root">
  <div class="container mt-5">
    <div class="row">
      <div class="col-md-4">
        <div class="list-group">
          <a href="#" class="list-group-item list-group-item-action"
            ><div class="d-flex w-100 justify-content-between">
              <h5 class="mb-1">珍珠奶茶</h5>
              <small>$50</small>
            </div>
            <p class="mb-1">香濃奶茶搭配QQ珍珠</p></a
          ><a href="#" class="list-group-item list-group-item-action"
            ><div class="d-flex w-100 justify-content-between">
              <h5 class="mb-1">冬瓜檸檬</h5>
              <small>$45</small>
            </div>
            <p class="mb-1">清新冬瓜配上新鮮檸檬</p></a
          ><a href="#" class="list-group-item list-group-item-action"
            ><div class="d-flex w-100 justify-content-between">
              <h5 class="mb-1">翡翠檸檬</h5>
              <small>$55</small>
            </div>
            <p class="mb-1">綠茶與檸檬的完美結合</p></a
          ><a href="#" class="list-group-item list-group-item-action"
            ><div class="d-flex w-100 justify-content-between">
              <h5 class="mb-1">四季春茶</h5>
              <small>$45</small>
            </div>
            <p class="mb-1">香醇四季春茶，回甘無比</p></a
          ><a href="#" class="list-group-item list-group-item-action"
            ><div class="d-flex w-100 justify-content-between">
              <h5 class="mb-1">阿薩姆奶茶</h5>
              <small>$50</small>
            </div>
            <p class="mb-1">阿薩姆紅茶搭配香醇鮮奶</p></a
          ><a href="#" class="list-group-item list-group-item-action"
            ><div class="d-flex w-100 justify-content-between">
              <h5 class="mb-1">檸檬冰茶</h5>
              <small>$45</small>
            </div>
            <p class="mb-1">檸檬與冰茶的清新組合</p></a
          ><a href="#" class="list-group-item list-group-item-action"
            ><div class="d-flex w-100 justify-content-between">
              <h5 class="mb-1">芒果綠茶</h5>
              <small>$55</small>
            </div>
            <p class="mb-1">芒果與綠茶的獨特風味</p></a
          ><a href="#" class="list-group-item list-group-item-action"
            ><div class="d-flex w-100 justify-content-between">
              <h5 class="mb-1">抹茶拿鐵</h5>
              <small>$60</small>
            </div>
            <p class="mb-1">抹茶與鮮奶的絕配</p></a
          >
        </div>
      </div>
      <div class="col-md-8">
        <table class="table">
          <thead>
            <tr>
              <th scope="col" width="50">操作</th>
              <th scope="col">品項</th>
              <th scope="col">描述</th>
              <th scope="col" width="90">數量</th>
              <th scope="col">單價</th>
              <th scope="col">小計</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><button type="button" class="btn btn-sm">x</button></td>
              <td>四季春茶</td>
              <td><small>香醇四季春茶，回甘無比</small></td>
              <td>
                <select class="form-select">
                  <option value="1">1</option>
                  <option value="2">2</option>
                  <option value="3">3</option>
                  <option value="4">4</option>
                  <option value="5">5</option>
                  <option value="6">6</option>
                  <option value="7">7</option>
                  <option value="8">8</option>
                  <option value="9">9</option>
                  <option value="10">10</option>
                </select>
              </td>
              <td>45</td>
              <td>45</td>
            </tr>
            <tr>
              <td><button type="button" class="btn btn-sm">x</button></td>
              <td>翡翠檸檬</td>
              <td><small>綠茶與檸檬的完美結合</small></td>
              <td>
                <select class="form-select">
                  <option value="1">1</option>
                  <option value="2">2</option>
                  <option value="3">3</option>
                  <option value="4">4</option>
                  <option value="5">5</option>
                  <option value="6">6</option>
                  <option value="7">7</option>
                  <option value="8">8</option>
                  <option value="9">9</option>
                  <option value="10">10</option>
                </select>
              </td>
              <td>55</td>
              <td>55</td>
            </tr>
          </tbody>
        </table>
        <div class="text-end mb-3">
          <h5>總計: <span>$100</span></h5>
        </div>
        <textarea
          class="form-control mb-3"
          rows="3"
          placeholder="備註"
        ></textarea>
        <div class="text-end">
          <button class="btn btn-primary">送出</button>
        </div>
      </div>
    </div>
    <hr />
    <div class="row justify-content-center">
      <div class="col-8">
        <div class="card">
          <div class="card-body">
            <div class="card-title">
              <h5>訂單</h5>
              <table class="table">
                <thead>
                  <tr>
                    <th scope="col">品項</th>
                    <th scope="col">數量</th>
                    <th scope="col">小計</th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <td>翡翠檸檬</td>
                    <td>7</td>
                    <td>385</td>
                  </tr>
                  <tr>
                    <td>冬瓜檸檬</td>
                    <td>7</td>
                    <td>315</td>
                  </tr>
                  <tr>
                    <td>冬瓜檸檬</td>
                    <td>4</td>
                    <td>180</td>
                  </tr>
                </tbody>
              </table>
              <div class="text-end">備註: <span>都不要香菜</span></div>
              <div class="text-end">
                <h5>總計: <span>$145</span></h5>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
```

資料：

```html
const data = [
  {
    "id": 1,
    "name": "珍珠奶茶",
    "description": "香濃奶茶搭配QQ珍珠",
    "price": 50
  },
  {
    "id": 2,
    "name": "冬瓜檸檬",
    "description": "清新冬瓜配上新鮮檸檬",
    "price": 45
  },
  {
    "id": 3,
    "name": "翡翠檸檬",
    "description": "綠茶與檸檬的完美結合",
    "price": 55
  },
  {
    "id": 4,
    "name": "四季春茶",
    "description": "香醇四季春茶，回甘無比",
    "price": 45
  },
  {
    "id": 5,
    "name": "阿薩姆奶茶",
    "description": "阿薩姆紅茶搭配香醇鮮奶",
    "price": 50
  },
  {
    "id": 6,
    "name": "檸檬冰茶",
    "description": "檸檬與冰茶的清新組合",
    "price": 45
  },
  {
    "id": 7,
    "name": "芒果綠茶",
    "description": "芒果與綠茶的獨特風味",
    "price": 55
  },
  {
    "id": 8,
    "name": "抹茶拿鐵",
    "description": "抹茶與鮮奶的絕配",
    "price": 60
  }
]
```