---
# System prepended metadata

title: React 概述
tags: [GDG 前端技術講座]

---

# React 概述
<center><img src="https://miro.medium.com/v2/resize:fit:1400/0*y6IcBe5J1AdALzXw.png" /></center>

## 前言

在我們今天的主角 React 登場之前，我們先來聊聊一個更根本的概念：「什麼是前端框架？」

在網頁開發的早期，我們就是用這三樣東西「純手工」打造網頁。
* 用 HTML 刻出骨架。
* 用 CSS 加上美觀的樣式。
* 用 JavaScript (我們常說的 Vanilla JS) 來增加互動，像是「點擊按鈕後，跳出一個視窗」。

這在製作簡單的靜態網站時，完全沒問題。

但是，當網頁應用 (Web App) 變得越來越複雜——想想看 Gmail、Google Maps 或是 Facebook，我們開始開發這類網站時將會遇到巨大的麻煩。

想像一下，你正在用純 JavaScript 開發一個像 Facebook 這樣的動態牆：

* 有幾十個「讚」按鈕，每個都要獨立計數。
* 有人留言，列表要「即時」更新，不用重新整理頁面。
* 右上角的「通知」圖示要顯示未讀訊息的「紅點」。
![image](https://hackmd.io/_uploads/HJY1N5y1Ze.png)![image](https://hackmd.io/_uploads/ryFWVqykWg.png)![image](https://hackmd.io/_uploads/ByQlE51yZx.png)


如果你真的利用純 JavaScript 去開發邏輯部分的話，你很快就會發現，你的 JavaScript 程式碼變得一團混亂：

* DOM 操作地獄： 你會寫滿 <code>document.getElementById</code> 和 <code>.addEventListener</code>。
* 狀態管理混亂： 你的資料（例如：按讚數、留言列表）散落在各處。當資料更新時，你必須「手動」記得去更新畫面上 所有 相關的地方。
* 難以維護： 程式碼牽一髮動全身，修改一個小功能，可能導致另一個地方壞掉。

**而以上就是「前端框架」誕生的原因。**

前端框架幫我們**能夠更有結構化、更方便的去開發網站**。

主流的前端框架有分很多種像是 React、Vue、Angular 等等，那麼我們這次的主角就是 **React**。

## 核心概念 (一) - 元件化 (Component-based)

### 甚麼是元件 (Component)
就像是你玩樂高積木一樣，能夠把複雜的 UI 變成一個可以重複使用的積木。例如: <code>NavBar</code>、<code>Card</code>、<code>Button</code>。

### JSX 語法擴充 - 寫在 JavaScript 中的「HTML」
傳統的 HTML 與 Javascript 是不能夠寫在一起的，所以每次當你要去操作網頁中的某個物件的時候，每次都要手動操作 DOM (<code>document.getElementById...</code>)，如果你做的網頁很大，那麼這會變得非常的麻煩。所以有了 JSX，我們網頁的 UI 結構和邏輯（例如 map 產生列表）可以寫在一起，非常直觀。

### Function Component (函數式元件)
**Function Component 就是一個普通的 JavaScript 函式 (Function)。**
它接受一個名為 `props` (屬性) 的物件作為參數，然後**回傳 (return)** 描述你想在螢幕上看到什麼的 **React 元素 (通常是 JSX)**。


### Props (屬性)：元件間的溝通
* 概念： 父母 (Parent Component) 傳遞資料給小孩 (Child Component) 的方式。
* 特性： 單向資料流 (One-Way Data Flow)、唯讀 (Read-Only)。
* 範例： 定義一個 <code>Button</code> 組件， 假設<code><Button text="點我" color="blue" /></code>，那麼其中 <code>text</code> 與 <code>color</code> 為 <code>Button</code> 這個元件的 Props

### 範例 - 介紹卡片 (虛擬碼)
#### 不使用 React
```html=
<body>
    <h1>我們的團隊</h1>
    <div class="card">
        <img src="https://via.placeholder.com/150" alt="用戶頭像">
        <h3>Alice</h3>
        <p>我是一個前端工程師。</p>
    </div>
    <div class="card">
        <img src="https://via.placeholder.com/150" alt="用戶頭像">
        <h3>Bob</h3>
        <p>我是一個後端工程師。</p>
    </div>
    <div class="card">
        <img src="https://via.placeholder.com/150" alt="用戶頭像">
        <h3>Stacy</h3>
        <p>我是一個 PM。</p>
    </div>
</body>
```

#### 使用 React
<code>ProfileCard.js</code>
```javascript=
import React from 'react';

// 這就是一個「元件」
// 它是一個函式，會接收一個 props 物件 (裡面放著外面傳進來的資料)
// 然後回傳它該長什麼樣子的 JSX
function ProfileCard(props) {
    return (
        <div className="card">
            <img src={props.imageUrl} alt="用戶頭像" />
            <h3>{props.name}</h3>
            <p>{props.description}</p>
        </div>
    );
}

export default ProfileCard;
```

<code>App.js</code>
```javascript=
import React from 'react';
import ProfileCard from './ProfileCard'; // 載入我們剛剛做的卡片元件
import './styles.css'; // 假設 CSS 樣式跟 HTML 範例一樣

// 這是主要的 App 元件
function App() {
    const profileData = [
        { 
            name: "Alice", 
            description:"我是一個前端工程師", 
            imageUrl: "https://via.placeholder.com/150"
        },
        { 
            name: "Bob", 
            description:"我是一個後端工程師", 
            imageUrl: "https://via.placeholder.com/150"
        },
        { 
            name: "Stacy", 
            description:"我是一個 PM", 
            imageUrl: "https://via.placeholder.com/150"
        }
    ]
    return (
        <div>
            <h1>我們的團隊</h1>

            {profileData.map(profile => (
                <ProfileCard 
                    key={profile.name}
                    name={profile.name}
                    description={profile.description}
                    imageUrl={profile.imageUrl}
                />
            ))}
        </div>
    );
}

export default App;
```

## 核心概念 (二) - 狀態與生命週期 (State & Hooks)

### State (狀態)：讓元件擁有自己的「記憶體」
* 概念： 讓元件「記住」事情的機制（例如：計數器、輸入框的文字）。
* 關鍵： 當 State 改變時，React 會自動重新渲染 (Re-render) 元件。 (這是 React 的魔法核心！)

那我們要怎麼去讓元件自己的狀態呢 ? 這時候 Hooks 登場了

### Hooks 登場：讓函式元件 (Functional Component) 擁有超能力
#### useState（）：
* 功能：讓元件能夠有自己的狀態 (state)
* 範例：以下是一個簡單的「計數器」按鈕，展示 [count, setCount] 的用法。
```javascript=
import React from "react";

export default function CustomizedButton() {
    const [count, setCount] = React.useState(0)
    
    const clickHandler = () => {
        setCount(count + 1);
    }
    
    return (
        <div>
            <h1>This Button has State</h1>
            <button onClick={clickHandler}>Click Count : {count}</button> 
        </div>
    )
}
```

#### useEffect（）：
* 功能：處理「副作用」(Side Effects)。
* 什麼是副作用？ 就是任何「渲染畫面」以外的事情。
* 常見的副作用：
    * 向資料庫讀取資料 (Data Fetching)。
    * 設定計時器 (<code>setTimeout</code>)。
    * 手動操作 DOM。
* 總之，<code>useEffect</code>就是將這些 **「與渲染無關，但又必須執行的操作」** 從純粹的渲染邏輯中分離出來，並允許你在組件的生命週期（掛載、更新、卸載）中，以可預測且受控的方式執行它們。
* 範例：以下是一個簡單的 data fetch 模擬並且記錄 data fetching 的次數。
```javascript=
import React from "react";

export default function CustomizedButton() {
    const [count, setCount] = React.useState(0)
    const [toggle, setToggle] = React.useState(false);
    
    const clickHandler = () => {
        setCount(count + 1)
        setToggle(!toggle);
    }

    // Mocking data fetching with useEffect
    React.useEffect(() => {
        let message = "Data fetching...";
        console.log(message);

        const timer = setTimeout(() => {
            message = "Fetching complete!";
            console.log(message);
        }, 2000);

        return () => {
            clearTimeout(timer);
        }
    }, [toggle]);
    
    return (
        <div>
            <h1>This Button has State</h1>
            <button onClick={clickHandler} className="custom-btn">Fetch Count : {count}</button> 
        </div>
    )
}
```

## 核心概念 (三) - React 的「快」，為什麼？
* Virtual DOM (虛擬 DOM)
    * 問題： 頻繁且大量地直接操作「真實 DOM」非常昂貴（效能差）。
    * React 的解法：
        * 在 JavaScript 記憶體中，建立一個「虛擬」的 DOM 結構 (V-DOM)。
        * 當 State 改變時，React 建立一個 新的 V-DOM。
        * Diffing Algorithm (差異比對)： React 快速比對「舊 V-DOM」和「新 V-DOM」的差別。
        * Reconciliation (調節)： 只把 真正有改變 的部分，一次性地更新到「真實 DOM」上。
* 比喻： 你不是重蓋整棟房子(**操作 Real-DOM**)，你只是找到哪片油漆剝落了，然後只補那塊漆(**操作 Virtual DOM**)。

---
文件參考：https://react.dev/reference/react


