---
# System prepended metadata

title: 第三週

---

# 第三週

本頁連結：https://hackmd.io/5pPUaGDdS5G6vnLOrNUKqA

## 課前說明

- 上週的挑戰抽出名單

```
function drawNumber(maxValue) {
    if (maxValue <= 0 || !Number.isInteger(maxValue)) {
        throw new Error("請傳入一個大於 0 的整數！");
    }
    return Math.floor(Math.random() * maxValue) + 1;
}
```

- 明天的活動： [數位職涯博覽會 / AI 人才高峰會](https://www.yourator.co/2025-careerfair)

預計出現時間：早上 9:30 ~ 17:00
![貼上的影像_2025_1_10_14_02](https://hackmd.io/_uploads/BkEUdN0Lyx.png)

會提供哪些服務呢？
- 履歷健檢
- 職涯諮詢
- 適性測驗 + 解說

## 本週目標

- React 基本元件
    - JSX
    - Vite 中的樣式匯入
- React Hook
    - useState
    - React 的生命週期...
    - useEffect
    - useRef 操作 DOM 元素


## 從零手動建立元件

React 都是元件，掌握建立一個元件的觀念，將有助於學習建構所有元件

### 建立元件起手式

1. 開啟檔案
2. 建立函式元件，並使用 `export default` 進行匯出
```html
function Component() {
  return (<></>)
}

export default Component;
```
3. 使用 import 匯入，並使用 <… /> 搭配元件名稱加入至畫面上
    
```html
import Component from '../Component';

function App() {
    return (<>
        <Component />
    </>)
}
```

### 常見 JSX 問題

1. 定義元件一定是大寫
    - 這在 React 中是一個慣例，避免與一般函式搞混
2. 多個元素外層需要使用標籤包覆，或使用 React.Fragment
    - 差異：Fragment 可以帶 key，`<>` 不能
3. 沒有正確結尾，結尾不正確
4. html 屬性轉換名稱運用要正確（使用小駝峯）
5. return 建議加入括號

保留字
<table><thead><tr><th><strong>HTML 屬性</strong></th><th><strong>React 中的 JSX 屬性名稱</strong></th><th><strong>原因</strong></th></tr></thead><tbody><tr><td><code>class</code></td><td><code>className</code></td><td><code>class</code> 是 JavaScript 的保留字</td></tr><tr><td><code>for</code></td><td><code>htmlFor</code></td><td><code>for</code> 是 JavaScript 的保留字</td></tr><tr><td><code>onclick</code></td><td><code>onClick</code></td><td>React 中事件名稱遵循駝峰命名規則</td></tr><tr><td><code>onchange</code></td><td><code>onChange</code></td><td>React 中事件名稱遵循駝峰命名規則</td></tr><tr><td><code>maxlength</code></td><td><code>maxLength</code></td><td>React 中屬性名稱遵循駝峰命名規則</td></tr><tr><td><code>minlength</code></td><td><code>minLength</code></td><td>React 中屬性名稱遵循駝峰命名規則</td></tr><tr><td><code>tabindex</code></td><td><code>tabIndex</code></td><td>React 中屬性名稱遵循駝峰命名規則</td></tr><tr><td><code>readonly</code></td><td><code>readOnly</code></td><td>React 中屬性名稱遵循駝峰命名規則</td></tr><tr><td><code>autocomplete</code></td><td><code>autoComplete</code></td><td>React 中屬性名稱遵循駝峰命名規則</td></tr><tr><td><code>autofocus</code></td><td><code>autoFocus</code></td><td>React 中屬性名稱遵循駝峰命名規則</td></tr><tr><td><code>spellcheck</code></td><td><code>spellCheck</code></td><td>React 中屬性名稱遵循駝峰命名規則</td></tr><tr><td><code>contenteditable</code></td><td><code>contentEditable</code></td><td>React 中屬性名稱遵循駝峰命名規則</td></tr><tr><td><code>aria-*</code></td><td>無需更改</td><td><code>aria-*</code> 屬性可以直接使用</td></tr><tr><td><code>data-*</code></td><td>無需更改</td><td><code>data-*</code> 屬性可以直接使用</td></tr></tbody></table>


### 在 Vite 中匯入樣式

**外部樣式**

1. 在 assets 加入 all.scss 或 all.css
2. 在 main.jsx 或元件中進行匯入 `import './assets/all.css'`   
3. 如果是 .scss 檔案，則需要使用 `npm install -D sass-embedded` 安裝擴充套件

**行內樣式**

1. 使用物件定義 `style={{ ... }}`
2. 樣式屬性使用 小駝峯命名，例如：`backgroundImage`
3. 值則是字串


## React Hook

### useState

更深入認識 useState

1. React 的生命週期：React 在每次更新資料時，會完整刷新元件，影響：
    - 函式會被完整重新運行
    - 不是使用 useState 建立的資料，會被重置
    - 函式可能會被多次重新註冊（例如：setTimeout）
2. 不可以在元件內直接使用 setState：因為每次更新都會刷新元件
3. 更新是非同步的：無法再更新的當下取得更新後的資料
4. **更新是採用覆蓋的形式**
    - 所有資料都是採用覆蓋，而不是用參考修改其值

![空白](https://hackmd.io/_uploads/ByuDWi0Iye.png)


### useEffect

React 用來管理生命週期、監聽的方法，相當於 Vue 的 onMounted, Watch

基本撰寫方式
```html
useEffect(setup, [dependencies])
```

- setup 是觸發的函式方法
- dependencies 則是監聽的值（~~依賴~~ 相依陣列 ❤️）

**延伸知識：**

- useEffect 的觸發時間點，必須正確加入 []
    - 沒加，這會引發不必要的錯誤
    - `[]` 空值：僅會在初始化時觸發
    - `[dependencies]` ：初始化及特定值更新時觸發
- useEffect callback 本身不能作為 async function 使用
    - 就… 不行
- useEffect 避免無限循環：避免在`[dependencies]` 監聽該 useEffect 中特定的 set 值
    - 範例
```jsx
useEffect(() => {
  setId('123')
}, [id])
```
    
- 因為 useEffect 可能會重複註冊 setup 內的內容，所以必須使用 return 取消特定註冊

**實戰運用情境：**

- 取得 DOM 元素
- 初始化搭配 useEffect 來發送請求

### useRef

基本語法：

```jsx
const ref = useRef(initialValue)
```

**useRef 可以用來做什麼**

- 透過 useRef 取得 DOM 元素
    - useEffect 有作用域問題，取得值難以傳遞至另一個函式中
    - 未來畫面上可能有多個同名元素（元件化以後），透過 useRef 可以取得正確的元素
- 不受 useState 的生命週期影響，透過 useRef 保存特定值（可參考預習課程）

**useRef 實戰：**

- 操作 DOM（以 chart.js 為例
    - https://www.chartjs.org/docs/latest/
    - 案例：*https://www.chartjs.org/docs/latest/getting-started/usage.html*
- 操作 Bootstrap Modal
    - 關於 Bootstrap Modal 的新增問題：https://github.com/twbs/bootstrap/issues/41005
        - 解方：
```
modal.addEventListener('hide.bs.modal', () => {
  if (document.activeElement instanceof HTMLElement) {
    document.activeElement.blur();
  }
});
```
> 這段程式碼可以將焦點從 modal 中移除

## 實戰：

1. 取得遠端資料，並使用列表呈現
2. 點擊 Modal 展開特定資料


## 本週額外挑戰

- 預習章節閱讀：[連結](https://rpg.hexschool.com/#/training/12062543649513962870/board/content/12062543649513962883_12062543649513962890)
    - React 元件基礎
    - React hooks
- 作業連結：https://rpg.hexschool.com/#/training/12062543649513962870/board/content/12062543649513962871_12062543649513962892?tid=12062543649528303606
    - 助教作業解說（週日上午 10:00）
    ![image](https://hackmd.io/_uploads/BkXeKpsSke.png)
- 團隊任務：
    - https://rpg.hexschool.com/#/training/12062543649513962870/board/content/12062543649513962877_12062543649513962905

## 寫作業心法教學

#### 1. 先列出開發需要做哪些事
範例：
1. 製作所有版型
2. 串接登入功能
3. 轉到產品列表頁面
4. 取得所有產品列表的 API 串接
5. 彈出 Modal
6. 彈出 Modal 並取得單一產品資料
7. 串接更新資料 API
8. 關閉 Modal
9. 刪除功能製作...

#### 2. 開始一一擊破，然後把完成的部分打勾

1. 製作所有版型 v

#### 3. 定期審視，如果有與原本規劃不同之處，就重新修正需要開發的項目

## 挑戰

升級禮物（把握這次，再給下去會沒 $$）

- 預設兩位名額
- 超過 40 人 + 1 位名額，之後每 20 人均 + 1 名額

![image](https://hackmd.io/_uploads/HJffXBRI1l.png)


課程 API 資料建構，完成以下條件並分享至 Discord 頻道，分享內容：
```
序號：0
我是 xxx
連結： GitHub Pages 連結
執行順序：
1. 製作所有版型 5mins
2. 串接登入功能 1hr
3. 轉到產品列表頁面 10mins
4. 取得所有產品列表的 API 串接 10mins
5. 彈出 Modal 10mins
6. 彈出 Modal 並取得單一產品資料 10mins
7. 串接更新資料 API 10mins
8. 關閉 Modal 10mins
9. 刪除功能製作... 10mins

完成總花費： 3hrs(不用精準，大約即可)
心得：透過一個個列點，真的比較清楚功能該如何完成
```

### 審核條件

1. 需要完成第三週作業，並上傳至 GitHub Pages（抽獎時會進行驗證，需確保可以登入、可以列出品項、可以打開 Modal 等功能）
2. 需要列出自己的開發順序及標上時間，不需要與卡斯伯的範例相同
3. 本次需要撰寫心得，與大家分享列點開發是否有效
4. 可參考範例答案、助教解說，禁止直接複製程式碼