跳至主要内容

37 篇文章 含有標籤「react」

檢視所有標籤

React JSX 入門教學 | w3schools 學習筆記

· 閱讀時間約 2 分鐘
kdchang

前言

React 是一個用於建立 UI 元件的 JavaScript 函式庫,而 JSX 則是屬於 React 中的一個元件模板語法糖。這篇文章將簡要介紹 JSX 是什麼,如何撰寫、條件式使用以及特殊對應,幫助初學者或 React 開發者進一步瞭解 JSX 的基礎應用。

重點摘要

  • JSX 是 JavaScript XML 的縮寫
  • 允許在 JavaScript 代碼中直接寫 HTML
  • JSX 會被轉譯變成 React.createElement()
  • JSX 中的 HTML 項目必須有唯一的層級結點
  • 可用小括號 執行 JavaScript 表達式
  • 允許使用 fragment (空括號) 以避免額外 DOM 結構
  • HTML 元素必須適當關閉,並使用 className 代替 class
  • 使用條件語句時, if 必須在 JSX 之外,可用三元表達式

實例解說

  1. JSX 與非 JSX 寫法

使用 JSX 的方式:

const myElement = <h1>I Love JSX!</h1>;
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(myElement);

未使用 JSX 的方式:

const myElement = React.createElement('h1', {}, 'I do not use JSX!');
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(myElement);
  1. JSX 表達式範例

使用 JSX 方式計算數學表達式:

const myElement = <h1>React is {5 + 5} times better with JSX</h1>;
  1. 多行 HTML 要用 () 包起
const myElement = (
<ul>
<li>Apples</li>
<li>Bananas</li>
<li>Cherries</li>
</ul>
);
  1. 唯一一層級結點要求
const myElement = (
<div>
<p>I am a paragraph.</p>
<p>I am a paragraph too.</p>
</div>
);

或是使用 fragment :

const myElement = (
<>
<p>I am a paragraph.</p>
<p>I am a paragraph too.</p>
</>
);
  1. 元素必須適當關閉
const myElement = <input type="text" />;
  1. 使用 className 代替 class
const myElement = <h1 className="myclass">Hello World</h1>;
  1. JSX 條件語句

方式 1:使用 if 在 JSX 之外

const x = 5;
let text = 'Goodbye';
if (x < 10) {
text = 'Hello';
}
const myElement = <h1>{text}</h1>;

方式 2:使用三元表達式

const x = 5;
const myElement = <h1>{x < 10 ? 'Hello' : 'Goodbye'}</h1>;

參考文件

  1. React Custom Hooks

React Render HTML 入門教學 | w3schools 學習筆記

· 閱讀時間約 2 分鐘
kdchang

前言

React 是一個專門用於構建使用者介面(UI)的 JavaScript 函式庫,其主要目標就是將 HTML 呈現在網頁中。透過 React 的核心函式 createRoot() 和方法 render(),開發者可以將 UI 元件渲染到指定的 HTML 元素中。本文將介紹 React 如何在網頁上渲染 HTML,包括核心函式與方法的用途、應用位置與語法示範,並介紹與 JSX 語法的結合使用方式。

重點摘要

  • React 透過 createRoot() 函式與 render() 方法將 HTML 渲染到網頁上。
  • createRoot() 用於指定要渲染的目標 HTML 元素。
  • render() 用於將 React 元件實際渲染到指定元素中。
  • 標準的 React 專案會在 public/index.html 中提供 <div id="root"> 作為渲染容器。
  • JSX 語法允許開發者在 JavaScript 中撰寫類似 HTML 的程式碼。
  • 根節點不必一定是 <div>,也不一定要命名為 root

實際範例

  1. 渲染一段簡單的段落:
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<p>Hello</p>);

上述程式碼會將 "Hello" 文字渲染到 HTML 文件中的:

<body>
<div id="root"></div>
</body>
  1. 使用 JSX 撰寫 HTML 表格並渲染:
const myelement = (
<table>
<tr>
<th>Name</th>
</tr>
<tr>
<td>John</td>
</tr>
<tr>
<td>Elsa</td>
</tr>
</table>
);

const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(myelement);

此段程式會顯示一個包含名稱的簡單表格,渲染至 root 節點中。

  1. 更換根節點的標籤與 id: 不一定要使用 <div id="root"> 作為渲染節點,可以自行命名:
<body>
<header id="sandy"></header>
</body>

對應的 React 程式碼如下:

const container = document.getElementById('sandy');
const root = ReactDOM.createRoot(container);
root.render(<p>Hallo</p>);

此範例將段落渲染至 header 元素。

總結

React 的渲染邏輯核心在於兩個部分:定義渲染目標與執行渲染動作。透過 createRoot() 指定 HTML 元素、render() 注入 React 元件,開發者可以將 UI 動態顯示在任何節點上。搭配 JSX 語法,不僅可以撰寫更具可讀性的 UI 結構,也讓程式碼維護更為便利。

參考文件

  1. React Render HTML

React 與 ES6 語法教學入門 | w3schools 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

ES6(ECMAScript 2015)是 JavaScript 的第六版,於 2015 年發布,為 JavaScript 帶來了重大語法革新。React 作為現今最受歡迎的前端框架和函式庫之一,其核心設計與語法極度依賴 ES6 的各項功能。因此,學習 React 前,理解 ES6 的語法特性將大幅提升開發效率與理解深度。

本文將說明 React 常用的 ES6 特性,並透過簡明範例幫助你掌握其實作方式。

重點摘要

  • ES6 是 ECMAScript 第六版,又稱 ECMAScript 2015。

  • React 使用大量 ES6 語法,包括:

    • Class 類別
    • 箭頭函式
    • let、const 變數宣告
    • 陣列方法(如 .map)
    • 解構(Destructuring)
    • 模組系統(import/export)
    • 三元運算子(Ternary Operator)
    • 展開運算子(Spread Operator)

1. 類別與繼承(Classes & Inheritance)

ES6 引入了 class 關鍵字來定義類別:

class Car {
constructor(name) {
this.brand = name;
}
present() {
return 'I have a ' + this.brand;
}
}

const mycar = new Car('Ford');
console.log(mycar.present());

繼承使用 extends 關鍵字:

class Model extends Car {
constructor(name, model) {
super(name);
this.model = model;
}
show() {
return this.present() + ', it is a ' + this.model;
}
}

const mycar = new Model('Ford', 'Mustang');
console.log(mycar.show());

2. 箭頭函式(Arrow Functions)

簡化函式的寫法:

const hello = () => 'Hello World!';
const greet = (name) => `Hello ${name}`;

3. 變數宣告(let、const、var)

var x = 5; // 函式作用域
let y = 10; // 區塊作用域
const z = 15; // 常數,不可重新指派

const 宣告的是參考不可變:

const arr = [1, 2];
arr.push(3); // 可以修改內容

4. 陣列方法(Array.map)

在 React 中常用於渲染列表:

const fruits = ['apple', 'banana', 'orange'];
const listItems = fruits.map((fruit) => <p>{fruit}</p>);

5. 解構賦值(Destructuring)

解構陣列:

const vehicles = ['mustang', 'f-150', 'expedition'];
const [car, , suv] = vehicles;

解構函式回傳值:

function calc(a, b) {
return [a + b, a - b];
}

const [sum, diff] = calc(5, 3);

6. 展開運算子(Spread Operator)

複製或合併陣列與物件:

const numbers1 = [1, 2];
const numbers2 = [3, 4];
const all = [...numbers1, ...numbers2];

const car = { brand: 'Ford', color: 'red' };
const update = { color: 'blue' };
const updatedCar = { ...car, ...update };

7. 模組系統(Modules)

exportimport 用於模組化程式碼:

命名匯出:

// person.js
export const name = 'Jesse';
export const age = 40;
// 使用
import { name, age } from './person.js';

預設匯出:

// message.js
const message = () => 'Hello';
export default message;
import message from './message.js';

8. 三元運算子(Ternary Operator)

條件判斷簡化語法:

const isAuth = true;
isAuth ? renderApp() : renderLogin();

結語

ES6 為 JavaScript 帶來嶄新的語法與思維方式,也為 React 帶來強大的表達力與模組化能力。熟練掌握這些語法,將能讓你在開發 React 專案時更加順手、高效並撰寫出更具可維護性的程式碼。若你尚未熟悉這些語法,建議你從簡單的練習開始,搭配 React 實際開發經驗進行吸收與內化。

參考文件

  1. React ES6

React 入門教學 | w3schools 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

在當代的前端開發中,React 是最具代表性的 JavaScript 函式庫之一。由 Facebook 軟體工程師 Jordan Walke 所開發,React 被廣泛應用於建構動態使用者介面,尤其適用於大型單頁應用(SPA, Single Page Application)。本篇文章將帶你認識 React 的核心概念、其背後的工作原理、使用前的基礎知識與發展歷史,並透過實例進行初步實作。


重點摘要

  1. 什麼是 React?

    • React 是一個前端 JavaScript 函式庫,用來建構使用者介面(UI)。
    • React 的別稱包括 React.js 與 ReactJS。
    • 它專注於「元件化思維」,每個 UI 元素都被視為一個可重複使用的元件(Component)。
  2. React 如何運作?

    • React 在記憶體中建立一個「虛擬 DOM」(Virtual DOM)。
    • 所有 DOM 操作會先發生在虛擬 DOM 中,再批次更新實體 DOM。
    • 這樣的差異化更新策略可提升效能,只變更必要的部分。
  3. React 的優勢

    • 高效能:避免不必要的 DOM 操作。
    • 組件化:提升程式碼的重用性與可維護性。
    • 單向資料流:資料流動清晰易懂。
    • 強大社群與生態圈:大量開源資源與工具支援。
  4. 使用 React 前的必要基礎

    • 熟悉 HTML 結構與語意標記。
    • 理解 CSS 排版與樣式應用。
    • 掌握 JavaScript 基本語法與函數觀念(如 ES6 語法、變數宣告、陣列方法等)。
  5. React 的發展歷程

    • 2011 年:React 首次應用於 Facebook 的新聞動態功能(Newsfeed)。
    • 2013 年 7 月:React 對外發布首個公開版本 0.3.0。
    • 2024 年 12 月:React 最新穩定版本為 19.0.0。

實際範例

以下是一個簡單的 React 程式碼範例,展示如何建立與渲染一個元件。

// 引入 React 與 ReactDOM 函式庫
import React from 'react';
import ReactDOM from 'react-dom/client';

// 建立一個簡單的元件
function Welcome() {
return <h1>你好,React 世界!</h1>;
}

// 在指定的 DOM 節點中渲染該元件
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Welcome />);

解說:

  1. import React from 'react'; 是使用 React 所必須的匯入語句。
  2. Welcome 是一個函數式元件(Functional Component),回傳的是 JSX 語法。
  3. ReactDOM.createRoot 創建一個 root 對象,負責將元件掛載至網頁的 #root DOM 節點。
  4. root.render(<Welcome />) 是將我們的元件渲染到網頁中。

總結

React 是一個現代網頁開發的重要工具,特別適合構建具互動性與模組化結構的網頁。透過虛擬 DOM 技術,React 讓介面更新更有效率,並提供清晰的元件架構設計。對於有基本前端知識的開發者而言,React 是進階的最佳入門選擇之一。建議你在學習 React 前,先打好 HTML、CSS 與 JavaScript 的基礎,將能更順利掌握 React 的概念與應用。

接著我們將學習 React 的 JSX 語法、狀態管理(useState)、事件處理、生命週期(useEffect)等核心概念,逐步建立自己的 React 專案。

參考文件

  1. React Custom Hooks

React 前端整合 JWT(含 Refresh Token)入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

當你要將 JWT 驗證整合至 React 前端,並搭配 Refresh Token 或整合 OAuth(如 Google 登入)流程,你需要考慮前端的存儲方式、token 的更新機制,以及第三方登入的流程銜接。

以下將分成三個部分講解:


一、React 前端整合 JWT(含 Refresh Token)

流程總覽:

  1. 使用者輸入帳密登入,發送 /login 請求。

  2. 伺服器簽發兩種 token:

    • Access Token(短效,有效期如 15 分鐘)
    • Refresh Token(長效,有效期如 7 天)
  3. 前端儲存 Access Token(如在記憶體),Refresh Token 建議儲存在 HttpOnly Cookie

  4. 當 Access Token 過期時,自動用 Refresh Token 換取新 Access Token。

  5. 使用者主動登出時,Refresh Token 一併清除。


伺服器回傳範例(登入成功):

{
"accessToken": "xxxxx",
"expiresIn": 900
}

並透過 Set-Cookie 傳送 HttpOnly 的 Refresh Token:

Set-Cookie: refreshToken=xxxxx; HttpOnly; Path=/; Max-Age=604800;

React 實作要點

// login.js
import axios from 'axios';

export async function login(username, password) {
const res = await axios.post(
'/api/login',
{ username, password },
{
withCredentials: true, // 允許 cookie 傳遞
}
);

localStorage.setItem('accessToken', res.data.accessToken);
}

// api.js
import axios from 'axios';

const api = axios.create({
baseURL: '/api',
withCredentials: true,
});

api.interceptors.request.use((config) => {
const token = localStorage.getItem('accessToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});

api.interceptors.response.use(
(res) => res,
async (err) => {
if (err.response.status === 401) {
try {
// 嘗試使用 Refresh Token 換 Access Token
const res = await axios.post('/api/refresh', {}, { withCredentials: true });
localStorage.setItem('accessToken', res.data.accessToken);

// 重試原本請求
err.config.headers.Authorization = `Bearer ${res.data.accessToken}`;
return axios(err.config);
} catch (e) {
// refresh 失敗,跳轉登入頁
window.location.href = '/login';
return Promise.reject(e);
}
}
return Promise.reject(err);
}
);

export default api;

登出

export async function logout() {
await axios.post('/api/logout', {}, { withCredentials: true });
localStorage.removeItem('accessToken');
}

備註

  • Refresh Token 儲存在瀏覽器的 HttpOnly Cookie,無法被 JavaScript 存取,提升安全性。
  • Access Token 儲存在記憶體或 localStorage(但 localStorage 易受 XSS 攻擊)。
  • 若要完全防止 CSRF,Refresh Token cookie 需搭配 SameSite 設定與 CSRF token。

二、OAuth 2.0 登入(以 Google 為例)

流程總覽

  1. 前端點擊「使用 Google 登入」。
  2. 透過 Google OAuth 流程取得授權碼(或 id_token)。
  3. 前端將該 token 傳送到後端 /auth/google
  4. 後端驗證 Google id_token,並簽發 JWT 給前端。

React 前端整合(Google 登入)

使用 @react-oauth/google

npm install @react-oauth/google
import { GoogleOAuthProvider, GoogleLogin } from '@react-oauth/google';

function App() {
return (
<GoogleOAuthProvider clientId="你的 Google Client ID">
<GoogleLogin
onSuccess={(credentialResponse) => {
// 將 id_token 傳送給後端
fetch('/api/auth/google', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ token: credentialResponse.credential }),
});
}}
onError={() => {
console.log('登入失敗');
}}
/>
</GoogleOAuthProvider>
);
}

後端處理(Node.js + google-auth-library

import { OAuth2Client } from 'google-auth-library';
import jwt from 'jsonwebtoken';

const client = new OAuth2Client(GOOGLE_CLIENT_ID);

router.post('/auth/google', async (req, res) => {
const { token } = req.body;

const ticket = await client.verifyIdToken({
idToken: token,
audience: GOOGLE_CLIENT_ID,
});

const payload = ticket.getPayload();

const jwtToken = jwt.sign({ userId: payload.sub, name: payload.name }, process.env.JWT_SECRET, {
expiresIn: '15m',
});

const refreshToken = jwt.sign({ userId: payload.sub }, process.env.JWT_REFRESH_SECRET, {
expiresIn: '7d',
});

res
.cookie('refreshToken', refreshToken, {
httpOnly: true,
maxAge: 7 * 24 * 60 * 60 * 1000,
})
.json({ accessToken: jwtToken });
});

三、小結

功能JWT + RefreshOAuth 2.0
是否需要帳密登入否,透過第三方登入
Token 儲存Access Token: localStorage / memory
Refresh Token: HttpOnly Cookie
同上
適合對象自建會員系統使用 Google / Facebook / LINE 等快速登入
安全性良好,需搭配 HTTPS高,由 Google 等大廠管理
實作難度中等,需處理 Token 刷新邏輯中高,需處理外部驗證流程

延伸建議

  • 若你想使用前後端共用的 JWT 驗證邏輯,建議抽出 middleware 並集中處理。
  • 可搭配 jsonwebtokenaxios-auth-refresh 等工具。
  • 若前後端完全分離,建議使用跨網域 Cookie 搭配 SameSite=None; Secure

React Query 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

隨著前端應用程式越來越複雜,資料的取得、快取、同步更新以及狀態管理成為重要挑戰。傳統使用 useEffect 搭配 fetchaxios 取得資料,會讓程式碼變得冗長且難以維護,特別是需要處理快取、錯誤重試、背景重新整理(refetch)等功能時。

React Query 是一個強大的資料同步庫,它抽象並管理伺服器狀態(server state),讓你能輕鬆完成資料抓取、快取、更新與錯誤處理。透過簡潔的 API 和自動化行為,讓前端開發者能專注於業務邏輯,而非繁瑣的資料管理。

本篇教學將介紹 React Query 的核心概念,並提供簡單的實作範例,讓你快速理解如何在 React 專案中有效率且方便地使用 React Query。


重點摘要

  • React Query 是什麼? 專注於伺服器狀態管理的資料同步庫,提供資料取得、快取、自動重試、背景更新、分頁等功能。

  • 伺服器狀態(Server State) vs 本地狀態(Local State) React Query 管理的是伺服器端資料,不同於用 React 的 useState 管理元件內部的本地狀態。

  • 核心 Hook:useQuery 用來抓取和快取資料,接收一個 key 和一個 fetcher 函式,會自動處理 loading、error、資料快取。

  • 資料快取與自動同步 React Query 會自動快取請求結果,並依設定自動重新抓取,保持資料最新。

  • 背景重新整理(Refetching) 可設定在視窗獲得焦點時自動刷新資料,確保資料同步。

  • 錯誤重試機制 請求失敗時可自動重試,避免因網路波動導致資料錯誤。

  • useMutation 用於資料變更(新增、修改、刪除)操作,並支援變更後自動重新整理相關快取。

  • 全域 Query Client 使用 QueryClient 管理所有查詢狀態,需用 QueryClientProvider 包裹應用程式。

  • 方便整合各種請求函式庫 可搭配 fetchaxios 等任意資料請求方式。


實際範例

1. 安裝

npm install @tanstack/react-query

yarn add @tanstack/react-query

2. 基本設定

在 React 應用的根元件設定 QueryClientQueryClientProvider

import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

function App() {
return (
<QueryClientProvider client={queryClient}>
<YourComponent />
</QueryClientProvider>
);
}

export default App;

3. 使用 useQuery 抓取資料

import React from 'react';
import { useQuery } from '@tanstack/react-query';

// 一個模擬的 fetch 函式,從 API 取得使用者清單
async function fetchUsers() {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
}

function UserList() {
// 使用 useQuery,第一參數為 key,第二參數為 fetch 函式
const { data, error, isLoading, isError } = useQuery(['users'], fetchUsers);

if (isLoading) return <div>載入中...</div>;

if (isError) return <div>錯誤:{error.message}</div>;

return (
<ul>
{data.map((user) => (
<li key={user.id}>
{user.name} ({user.email})
</li>
))}
</ul>
);
}

export default UserList;

4. 使用 useMutation 進行資料更新

假設有一個新增使用者的 API,使用 useMutation 處理:

import React, { useState } from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';

async function addUser(newUser) {
const res = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
body: JSON.stringify(newUser),
headers: { 'Content-Type': 'application/json' },
});
if (!res.ok) throw new Error('新增失敗');
return res.json();
}

function AddUserForm() {
const [name, setName] = useState('');
const queryClient = useQueryClient();

const mutation = useMutation(addUser, {
onSuccess: () => {
// 新增成功後,重新整理 users 快取
queryClient.invalidateQueries(['users']);
},
});

const handleSubmit = (e) => {
e.preventDefault();
mutation.mutate({ name });
};

return (
<form onSubmit={handleSubmit}>
<input value={name} onChange={(e) => setName(e.target.value)} placeholder="使用者名稱" />
<button type="submit">新增使用者</button>
{mutation.isLoading && <p>新增中...</p>}
{mutation.isError && <p>錯誤:{mutation.error.message}</p>}
{mutation.isSuccess && <p>新增成功!</p>}
</form>
);
}

export default AddUserForm;

小結

React Query 提供一套完整且簡潔的 API 來管理伺服器狀態,包含資料取得、快取、錯誤處理與背景更新。透過 useQueryuseMutation,你能輕鬆地處理資料的讀取與更新,讓 React 應用程式更穩定且易維護。

建議在開發中逐步導入 React Query,取代傳統的 useEffect + fetch 模式,尤其是對於複雜的資料流與同步需求,能大幅提升開發效率與使用者體驗。

參考文件

  1. React Query 文件

React Compound Component 模式介紹與入門教學 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

在開發大型或複雜的 UI 元件時,傳統的 props 傳遞方式很容易導致元件層層嵌套、可讀性差與維護困難。Compound Component(複合元件)是一種設計模式,能提升 React 元件的可組合性與彈性。它讓父元件扮演「邏輯控制中心」的角色,子元件則能共享上下文資訊,專注於呈現。這種模式常見於設計系統或第三方 UI 套件(例如:<Tabs><Accordion><Dropdown> 等),能夠建立更清晰、有彈性的 API。


重點摘要

  • 定義:Compound Component 是一組彼此配合使用的 React 元件,透過共享上下文管理狀態與邏輯。

  • 優點

    • 增強元件 API 的彈性與可擴充性。
    • 父元件集中邏輯,子元件只負責 UI。
    • 避免 props drilling,提升可維護性。
  • 技術關鍵

    • 使用 React.createContext() 建立 Context。
    • 利用 Children.map 搭配 cloneElement 傳遞資料(進階用法)。
    • 常結合 static property 方式導出子元件(如 MyComponent.Header)。
  • 常見應用場景

    • Tabs 分頁元件
    • Accordion 折疊面板
    • Dropdown 下拉選單
    • Modal 對話框元件

實際範例:建立一個自訂的 <Toggle> 元件

此範例展示如何實作一個 Compound Component:<Toggle>, <Toggle.On>, <Toggle.Off>, <Toggle.Button>

1. ToggleContext.js

import { createContext, useContext } from 'react';

const ToggleContext = createContext();

export function useToggleContext() {
const context = useContext(ToggleContext);
if (!context) {
throw new Error('Toggle compound components must be used within <Toggle />');
}
return context;
}

export default ToggleContext;

2. Toggle.js

import { useState } from 'react';
import ToggleContext from './ToggleContext';

export function Toggle({ children }) {
const [on, setOn] = useState(false);
const toggle = () => setOn((prev) => !prev);

return <ToggleContext.Provider value={{ on, toggle }}>{children}</ToggleContext.Provider>;
}

Toggle.On = function ToggleOn({ children }) {
const { on } = useToggleContext();
return on ? children : null;
};

Toggle.Off = function ToggleOff({ children }) {
const { on } = useToggleContext();
return !on ? children : null;
};

Toggle.Button = function ToggleButton() {
const { on, toggle } = useToggleContext();
return <button onClick={toggle}>{on ? 'ON' : 'OFF'}</button>;
};

3. App.js(使用方式)

import { Toggle } from './Toggle';

export default function App() {
return (
<div>
<h1>Compound Component 範例</h1>
<Toggle>
<Toggle.On>狀態為:開啟</Toggle.On>
<Toggle.Off>狀態為:關閉</Toggle.Off>
<Toggle.Button />
</Toggle>
</div>
);
}

延伸說明

  • Context 的角色ToggleContext 扮演資訊橋梁,讓所有子元件能共用 on 狀態與 toggle 函式。
  • 錯誤處理useToggleContext 中若未包在 <Toggle> 裡使用,會主動拋出錯誤,提醒開發者正確使用上下文。
  • 可擴充性:我們可以進一步加入 <Toggle.Icon><Toggle.Label> 等元件,複用相同邏輯,保持一致行為。
  • 比傳統 Props 傳遞更清晰:使用 <Toggle.On> 等方式比 showOn={true} 更語意化且易於理解。

總結

Compound Component 是 React 開發中一個極具表達力與彈性的設計模式,尤其適用於 UI 元件庫的開發。透過 Context 的使用,我們能解耦邏輯與顯示元件,提升可讀性、可維護性與開發效率。雖然初期設計較為繁瑣,但一旦建立模式後,能帶來長遠效益,尤其在大型專案或多人協作的情境下更具價值。


延伸學習

  • React.cloneElement() 的進階應用(自動注入 props)
  • TypeScript 搭配 Compound Component 的型別設計
  • 使用 Zustand、Jotai 或 Redux 搭配 Compound Component