跳至主要内容

70 篇文章 含有標籤「frontend engineer」

檢視所有標籤

React Hooks useEffect 入門教學 | w3schools 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

在 React 函式型元件中,useEffect 是一個強大且常用的 Hook,用來處理副作用(side effects)。副作用指的是那些不直接涉及元件渲染的操作,例如:發送 API 請求、操作 DOM、設定或清除計時器等。

傳統上,這些操作會在 componentDidMountcomponentDidUpdatecomponentWillUnmount 等生命週期函式中進行,而在函式元件中,useEffect 正是用來統一處理這些行為。


重點摘要

  • useEffect 可以執行副作用操作,例如:抓取資料、設定計時器、監聽事件。
  • 語法格式:useEffect(函式, 依賴陣列)
  • 不提供第二個參數時,useEffect 每次重新渲染都會執行。
  • 傳入空陣列作為第二個參數,則只會在元件初次渲染時執行一次。
  • 若依賴陣列中包含特定的 state 或 props,只要它們改變,副作用就會重新執行。
  • 可以在 useEffect 裡透過回傳一個函式進行資源清除(cleanup),避免記憶體洩漏。

實際範例

範例一:沒有依賴陣列,導致每次渲染都執行

import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
setTimeout(() => {
setCount((count) => count + 1);
}, 1000);
});

return <h1>I've rendered {count} times!</h1>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Timer />);

問題說明:

  • 每次渲染都會重新執行 useEffect,導致 setTimeout 一直重複,數字不斷累加,非預期行為。

範例二:使用空陣列作為依賴,只執行一次

import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
setTimeout(() => {
setCount((count) => count + 1);
}, 1000);
}, []); // 加上空陣列,只在初始渲染時執行一次

return <h1>I've rendered {count} times!</h1>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Timer />);

重點:

  • 空陣列表示沒有任何依賴,因此只會在元件掛載時執行一次副作用。

範例三:有依賴變數,根據 count 改變而重新執行

import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';

function Counter() {
const [count, setCount] = useState(0);
const [calculation, setCalculation] = useState(0);

useEffect(() => {
setCalculation(() => count * 2);
}, [count]); // 每次 count 改變就重新計算

return (
<>
<p>Count: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>+</button>
<p>Calculation: {calculation}</p>
</>
);
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Counter />);

重點:

  • 依賴陣列中包含 count,因此只要 count 改變,useEffect 就會重新執行,計算新的值。

副作用的清除(Effect Cleanup)

某些副作用,如計時器、訂閱、事件監聽器等,當元件卸載或依賴改變時,應該清除,否則可能會導致記憶體洩漏或非預期行為。

useEffect 中可以回傳一個函式,用來執行清除動作。

範例四:清除計時器

import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
const timer = setTimeout(() => {
setCount((count) => count + 1);
}, 1000);

return () => clearTimeout(timer); // 清除 timeout
}, []);

return <h1>I've rendered {count} times!</h1>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Timer />);

說明:

  • setTimeout 被命名為 timer,在 useEffect 的清除函式中使用 clearTimeout(timer) 移除它,避免重複執行。

總結

React 的 useEffect 是處理副作用的主要工具。理解它的運作邏輯、依賴機制與清除策略,能幫助開發者更有效率地控制元件的生命周期與效能。

使用建議:

  • 若副作用只需在元件初次渲染執行,請傳入空陣列。
  • 若需要根據變數變動執行副作用,將其加入依賴陣列中。
  • 若副作用產生了外部資源(如計時器、訂閱等),務必記得清除。

掌握這些原則後,就能更靈活並安全地使用 useEffect,打造高效穩定的 React 應用。

參考文件

  1. React Custom Hooks

React Hooks useState 入門教學 | w3schools 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

在 React 函式元件中,useState 是最常用的 Hook 之一,能讓我們在無需使用 class 的情況下新增與管理元件的「狀態」(state)。狀態是指會隨著使用者互動或應用邏輯變化而更新的資料,例如:輸入框的內容、按鈕點擊次數、切換的主題顏色等。


重點摘要

  • useState 是 React 提供的 Hook,用來在函式型元件中儲存與更新狀態。
  • 使用前需先從 react 匯入 useState
  • useState(初始值) 會回傳一個陣列,包含目前的狀態值與更新狀態的函式。
  • 更新狀態請使用 setXXX 函式,不可直接修改狀態變數
  • 可以建立多個 useState 追蹤不同變數,也可使用一個物件整合多個欄位。
  • 若要更新物件或陣列的部分內容,應使用展開運算子(spread operator)來保留其他值。

實際範例

1. 匯入 useState

import { useState } from 'react';

使用時,請確認使用的是具名匯入(named import),useStatereact 模組的一部分。


2. 初始化狀態

function FavoriteColor() {
const [color, setColor] = useState('');
}

color 是目前狀態值;setColor 是修改此狀態的函式;初始值設定為空字串。


3. 讀取狀態並渲染

function FavoriteColor() {
const [color, setColor] = useState('red');

return <h1>My favorite color is {color}!</h1>;
}

此例中,畫面上會顯示 My favorite color is red!,透過 JSX 讀取狀態。


4. 使用按鈕更新狀態

function FavoriteColor() {
const [color, setColor] = useState('red');

return (
<>
<h1>My favorite color is {color}!</h1>
<button type="button" onClick={() => setColor('blue')}>
Blue
</button>
</>
);
}

點擊按鈕時,會透過 setColorcolor 更新為 "blue",畫面也會即時更新。


5. 多個狀態變數

function Car() {
const [brand, setBrand] = useState('Ford');
const [model, setModel] = useState('Mustang');
const [year, setYear] = useState('1964');
const [color, setColor] = useState('red');

return (
<>
<h1>My {brand}</h1>
<p>
It is a {color} {model} from {year}.
</p>
</>
);
}

這種方式使用多個 useState 管理多個欄位,彼此獨立。


6. 使用物件作為單一狀態

function Car() {
const [car, setCar] = useState({
brand: 'Ford',
model: 'Mustang',
year: '1964',
color: 'red',
});

return (
<>
<h1>My {car.brand}</h1>
<p>
It is a {car.color} {car.model} from {car.year}.
</p>
</>
);
}

以物件作為狀態,可集中管理多個欄位,也使程式碼更易維護。


7. 更新物件中的單一欄位

function Car() {
const [car, setCar] = useState({
brand: 'Ford',
model: 'Mustang',
year: '1964',
color: 'red',
});

const updateColor = () => {
setCar((prevState) => {
return { ...prevState, color: 'blue' };
});
};

return (
<>
<h1>My {car.brand}</h1>
<p>
It is a {car.color} {car.model} from {car.year}.
</p>
<button type="button" onClick={updateColor}>
Blue
</button>
</>
);
}

這裡使用展開運算子(...prevState)來保留其他屬性,僅更新 color。若直接使用 setCar({ color: "blue" }),會造成其他屬性遺失。


總結

React 的 useState 是建立互動式 UI 的基礎,能讓我們在函式型元件中管理狀態。透過這個 Hook,我們可以:

  • 初始化與讀取狀態值
  • 透過更新函式改變狀態並重新渲染畫面
  • 使用多個 useState 管理多個資料
  • 或整合為一個物件並使用展開運算子更新部分欄位

熟練掌握 useState 是學會 React 開發不可或缺的第一步。建議初學者透過實作各種小範例來加深理解與記憶。

參考文件

  1. React Custom Hooks

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

· 閱讀時間約 2 分鐘
kdchang

前言

Hooks 是在 React 16.8 版本中加入的新功能。Hooks 讓你可以在「函式元件(function components)」中使用狀態(state)以及其他 React 功能。因此,自從有了 Hooks 之後,類別元件(class components)通常就不再是必要的了

儘管 Hooks 幾乎取代了類別元件的使用方式,但 React 團隊目前並沒有打算移除 class 元件的支援。


什麼是 Hook?

Hooks 讓我們能夠「掛勾(hook into)」React 的核心功能,例如 狀態管理(state)生命週期方法(lifecycle methods)


範例:

import React, { useState } from 'react';
import ReactDOM from 'react-dom/client';

function FavoriteColor() {
const [color, setColor] = useState('red');

return (
<>
<h1>我最喜歡的顏色是 {color}</h1>
<button type="button" onClick={() => setColor('blue')}>
藍色
</button>
<button type="button" onClick={() => setColor('red')}>
紅色
</button>
<button type="button" onClick={() => setColor('pink')}>
粉紅色
</button>
<button type="button" onClick={() => setColor('green')}>
綠色
</button>
</>
);
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<FavoriteColor />);

在這個範例中,我們透過 useState 這個 Hook 來追蹤應用程式的狀態。

狀態(State):泛指那些會隨著使用者互動或應用邏輯而改變的資料或屬性。

此外,使用 Hook 前必須先從 react 模組中引入對應的函式,例如這裡的 useState


使用 Hook 的三大規則

  1. 只能在 React 的函式元件中呼叫 Hooks
  2. 只能在元件的最上層(Top-level)呼叫,不能寫在 iffor函式中等區塊內
  3. 不能有條件式地呼叫 Hook(例如不能寫在 if 判斷中)

注意:Hooks 無法在 class 類別元件中使用!


自訂 Hook(Custom Hooks)

如果你有一些包含狀態的邏輯(stateful logic),需要在多個元件之間重複使用,這時可以考慮封裝成自訂 Hook,以提升可讀性與重用性。

參考文件

  1. React Custom Hooks

在 React 中使用 Sass 進行樣式設計教學 | w3schools 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

在現代前端開發中,維護與管理 CSS 樣式是一項重要任務,尤其當應用程式日益龐大、元件複雜時,單純使用原生 CSS 經常會遇到樣式難以重用、命名衝突等問題。這時候,Sass(Syntactically Awesome Stylesheets)這類 CSS 預處理器便顯得格外實用。Sass 提供變數、巢狀語法、Mixin 等強大功能,有助於讓樣式更具模組化與可維護性。

本篇教學將說明如何在 React 專案中使用 Sass,從安裝、建立樣式檔案、到實際在元件中引用,手把手帶你完成設定。


重點摘要

  • Sass 是什麼:一種 CSS 預處理器,可在瀏覽器載入前編譯成標準 CSS。
  • 安裝方法:可透過 npm i sass 安裝 Sass 至 React 專案中。
  • 副檔名:Sass 檔案使用 .scss 副檔名。
  • 支援變數與函數:可使用 $變數@mixin 等進階語法撰寫樣式。
  • 與 React 整合方式:與 CSS 類似,透過 import './樣式.scss' 導入樣式。

Sass 是什麼?

Sass(Syntactically Awesome Stylesheets)是一種 CSS 的擴充語法,稱為 CSS 預處理器(preprocessor)。Sass 檔案會在伺服器端進行編譯,轉換為標準的 CSS,然後再由瀏覽器載入。

與傳統 CSS 相比,Sass 提供多種程式化的功能,包括:

  • 變數(Variables)
  • 巢狀語法(Nesting)
  • 混合(Mixins)
  • 繼承(Inheritance)

這些功能可以大幅簡化樣式維護與邏輯。


如何在 React 中使用 Sass?

若你使用 vite 建立專案,只需要簡單幾步即可在 React 中整合 Sass。

安裝 Sass

打開終端機,並在 React 專案目錄中執行以下指令:

npm i sass

安裝完成後,即可開始在專案中撰寫與導入 .scss 檔案。


建立 Sass 檔案

建立 .scss 檔案的方式與 CSS 相同,唯一差別是副檔名由 .css 改為 .scss

假設建立一個名為 my-sass.scss 的檔案,其內容如下:

// 定義一個變數
$myColor: red;

// 使用變數設定 h1 的文字顏色
h1 {
color: $myColor;
}

這段 Sass 程式碼定義了一個 $myColor 的變數,並將其應用於 h1 標題文字的顏色。


在 React 元件中使用 Sass

要在 React 元件中使用 Sass,只需像導入 CSS 檔案一樣導入 .scss 檔案即可。

以下是一個完整範例:

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './my-sass.scss'; // 導入 Sass 樣式檔

// 建立一個簡單的元件
const Header = () => {
return (
<>
<h1>Hello Style!</h1>
<p>Add a little style!.</p>
</>
);
};

// 掛載元件到畫面上
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);

只要這樣導入 Sass 檔案,該樣式就會自動被應用到對應的元素上,與原生 CSS 的使用方式幾乎一致。


延伸學習建議

若你對 Sass 有更進一步的興趣,建議深入學習以下主題:

  • Sass Mixin 的建立與使用
  • 巢狀規則與 BEM 命名法結合技巧
  • Sass 的分割與模組化導入(@import / @use)
  • 與 CSS Modules、Styled-components 等工具的比較與選擇

總結

Sass 為 CSS 帶來更多彈性與可維護性,是開發大型 React 應用時的重要利器。配合 vite 的簡單整合方式,即使是初學者也能快速上手。只需幾步就能建立出具備變數與結構邏輯的樣式系統,為專案帶來更清晰、可維護的樣式架構。

無論是個人 Side Project 或是商業應用,學會 Sass 的使用,將大大提升你在前端開發上的效率與品質。

參考文件

  1. React Custom Hooks
  2. React router 官方網站

React 中使用 CSS 的三種方式教學 | w3schools 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在開發 React 應用程式時,樣式的管理與設計是一項不可忽視的重要部分。雖然 React 是一個 JavaScript 函式庫,主要用於建構使用者介面,但它本身並不限制開發者如何為元件加上樣式。React 提供多種整合 CSS 的方法,這篇文章將會深入介紹三種最常見的樣式處理方式:行內樣式(Inline Styling)CSS 樣式表(Stylesheet)以及CSS 模組(CSS Modules),並說明每種方式的使用情境與範例。


重點摘要

  • React 支援使用 JavaScript 對元件進行行內樣式設計。
  • 傳統 CSS 樣式表可以與 React 搭配使用,只需匯入對應檔案。
  • 使用 CSS Modules 可避免樣式名稱衝突,適用於大型專案。

一、行內樣式(Inline Styling)

React 提供以 JavaScript 物件的方式設定行內樣式,這種方式最直接也最簡單,適合少量樣式或動態樣式情境。

實作範例:

const Header = () => {
return (
<>
<h1 style={{ color: 'red' }}>Hello Style!</h1>
<p>Add a little style!</p>
</>
);
};

**注意:**在 JSX 中,JavaScript 表達式必須寫在大括號 {} 內,而行內樣式本身是一個物件,因此需使用雙層大括號 {{}}


屬性名稱需使用 camelCase 命名方式

在 JavaScript 中無法使用帶有連字符(例如 background-color)的 CSS 屬性名稱,因此需轉換為 camelCase,例如:backgroundColor

實作範例:

const Header = () => {
return (
<>
<h1 style={{ backgroundColor: 'lightblue' }}>Hello Style!</h1>
<p>Add a little style!</p>
</>
);
};

使用樣式物件來管理樣式

若樣式較多,可先定義一個樣式物件,再以變數形式傳入 style 屬性中。

const Header = () => {
const myStyle = {
color: 'white',
backgroundColor: 'DodgerBlue',
padding: '10px',
fontFamily: 'Sans-Serif',
};

return (
<>
<h1 style={myStyle}>Hello Style!</h1>
<p>Add a little style!</p>
</>
);
};

二、CSS 樣式表(Stylesheet)

若你偏好將樣式與程式邏輯分離,傳統的 CSS 樣式表仍然是實用的選擇。只需建立 .css 檔案並在元件或主程式中匯入即可。

步驟一:建立 App.css 檔案

/* App.css */
body {
background-color: #282c34;
color: white;
padding: 40px;
font-family: Sans-Serif;
text-align: center;
}

**提示:**檔案名稱可以自由命名,但副檔名需為 .css

步驟二:匯入樣式表

// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './App.css';

const Header = () => {
return (
<>
<h1>Hello Style!</h1>
<p>Add a little style!</p>
</>
);
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);

這種方式與傳統 HTML 開發流程相似,適合簡單專案或共用樣式的情境。


三、CSS Modules

CSS Modules 是一種模組化的 CSS 寫法,每個 CSS 檔案的樣式只作用於匯入該檔案的元件,能有效避免樣式衝突,特別適合大型應用程式或多人協作的開發環境。

步驟一:建立模組化樣式檔案

建立一個名稱為 my-style.module.css 的 CSS 檔案:

/* my-style.module.css */
.bigblue {
color: DodgerBlue;
padding: 40px;
font-family: Sans-Serif;
text-align: center;
}

**注意:**檔案名稱需符合 *.module.css 格式,才能啟用模組功能。

步驟二:在元件中匯入模組

// Car.js
import styles from './my-style.module.css';

const Car = () => {
return <h1 className={styles.bigblue}>Hello Car!</h1>;
};

export default Car;

步驟三:匯入元件至主程式

// index.js
import ReactDOM from 'react-dom/client';
import Car from './Car.js';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car />);

透過這種方式,.bigblue 樣式只會應用於 Car 元件,其他元件不會受到影響。


總結

React 提供靈活的方式來處理樣式,你可以根據專案規模與開發需求選擇最適合的做法:

  • 小型元件或需動態切換樣式 → 行內樣式
  • 簡單專案或共用樣式 → 外部樣式表
  • 中大型專案或多人開發 → CSS Modules

透過良好的樣式管理方式,不僅可以提升 UI 的一致性與可維護性,也讓你能更專注於元件的邏輯設計。

如果你正開始學習 React,建議從行內樣式入手,漸進式學習 CSS Modules,將有助於建立健全的開發習慣與架構。

參考文件

  1. React Custom Hooks
  2. React router 官方網站

提升效能的利器:React.memo 使用入門教學 | w3schools 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在 React 中,當元件的父元件重新渲染時,預設情況下其所有子元件也會一併重新渲染,即便傳入的 props 完全沒變動。這種「不必要的重新渲染」若發生在大型應用中,會導致效能下降,尤其是當某些元件非常複雜、包含大量計算或 DOM 操作時。

為了避免這種情況,React 提供了一個高階元件函式:React.memo。這個函式能讓你記憶元件的輸出結果,當傳入的 props 沒有變更時,React 就會跳過該元件的重新渲染,達到提升效能的效果。


重點摘要

  • React.memo 可讓函式型元件根據 props 的淺層比較決定是否重新渲染
  • 適合用在接收不變 props 的純顯示元件
  • props 為函式、物件、陣列時,注意傳入參考要穩定,否則仍會觸發重新渲染
  • 效能提升明顯的情況:元件內容複雜、資料量大或頻繁更新的應用場景
  • 搭配 useCallbackuseMemo 可進一步優化

問題說明

以下是一個簡單的 React 應用,包含一個計數器與待辦事項列表元件(Todos):

index.js

import { useState } from 'react';
import ReactDOM from 'react-dom/client';
import Todos from './Todos';

const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState(['todo 1', 'todo 2']);

const increment = () => {
setCount((c) => c + 1);
};

return (
<>
<Todos todos={todos} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

Todos.js

const Todos = ({ todos }) => {
console.log('child render');
return (
<>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
</>
);
};

export default Todos;

在這個範例中,每當你點擊「+」按鈕讓 count 增加時,整個 App 元件重新渲染,而 Todos 元件也會一併被重新渲染,即使 todos 陣列完全沒有變更。你可以從 console log 中觀察到 child render 不斷出現。

若這個 Todos 元件變得很複雜,這樣的重新渲染就會造成效能浪費。


解法:使用 React.memo

要解決這個問題,我們可以使用 memoTodos 元件包裝起來,使其只有在 props.todos 變動時才會重新渲染。

修改 Todos.js

import { memo } from 'react';

const Todos = ({ todos }) => {
console.log('child render');
return (
<>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
</>
);
};

export default memo(Todos);

這裡我們引入 memo 並用它包裝元件。這樣一來,只要 todos 的內容沒有改變,Todos 元件就不會重新執行 render。


行為比較與效能提升說明

行為未使用 memo使用 memo
count 變更時重新渲染 Todos不重新渲染 Todos
todos 改變時重新渲染 Todos重新渲染 Todos
效能影響易造成浪費避免不必要更新

延伸說明

  • memo 比較的是 props 的淺層相等性。若傳入的是物件、函式等「參考型資料」,每次 render 都會被視為不同,仍然會觸發重新渲染。
  • 若要避免這種情況,可搭配 useMemouseCallback 讓 props 穩定。
  • memo 並非萬能,只有在元件內容複雜、render 成本高時,才明顯帶來效能優化。過度使用反而會增加記憶體與比較成本。

小結

React.memo 是 React 應用中常見的效能優化技巧之一。透過對 props 進行淺層比較,可以有效避免不必要的子元件重新渲染。當你的應用中包含大量重複渲染的靜態元件或資料時,適時使用 memo 可以大幅提升效能表現。

建議在開發時養成習慣:只有當元件的 props 確實可能不會變動,且 render 成本高時再使用 memo,讓效能優化達到真正效果。

參考文件

  1. React Custom Hooks
  2. React router 官方網站

使用 React Router 實現多頁面導覽功能教學(React Router v6)入門教學 | w3schools 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

React 是一個強大的 JavaScript 函式庫,專門用於建立使用者介面。不過,React 本身並未內建「頁面路由」功能。如果你想要為你的 React 專案加入多個頁面,例如首頁、部落格、聯絡我們頁面等等,就必須引入額外的工具。而在眾多路由解決方案中,React Router 是最受歡迎且廣泛使用的選擇。

本文將帶你從零開始,教你如何在使用 Create React App 建立的專案中導入 React Router,並建立一個基本的多頁面架構。


重點摘要

  • React 本身不包含頁面路由功能
  • React Router 是 React 中最常用的路由套件
  • React Router v6 是目前最新的主要版本
  • 需安裝 react-router-dom 套件來使用瀏覽器路由功能
  • 使用 <BrowserRouter>, <Routes>, <Route> 建立路由結構
  • 使用 <Outlet> 顯示巢狀路由對應的內容
  • 使用 <Link> 而非 <a> 進行頁面內部連結

安裝 React Router

在你的 React 專案根目錄下,打開終端機,執行以下指令安裝 React Router:

npm i -D react-router-dom

如果你是從 React Router v5 升級,建議加入 @latest 旗標:

npm i -D react-router-dom@latest

建立頁面資料夾與基本結構

為了建立多頁面應用,我們需要在 src 資料夾中新增一個 pages 資料夾,並在其中建立五個頁面元件:

src/pages/
├── Layout.js
├── Home.js
├── Blogs.js
├── Contact.js
└── NoPage.js

每個檔案都將包含一個簡單的 React 函式元件。


設定主路由(index.js)

src/index.js 中引入路由模組與頁面元件,並建立應用程式主結構:

import ReactDOM from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Layout from './pages/Layout';
import Home from './pages/Home';
import Blogs from './pages/Blogs';
import Contact from './pages/Contact';
import NoPage from './pages/NoPage';

export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="blogs" element={<Blogs />} />
<Route path="contact" element={<Contact />} />
<Route path="*" element={<NoPage />} />
</Route>
</Routes>
</BrowserRouter>
);
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

說明範例運作原理

  • <BrowserRouter>:外層包住整個路由結構,提供瀏覽器路由功能。
  • <Routes><Route>:定義所有路由規則與對應的元件。
  • 巢狀 <Route>Layout 元件作為共同外框,其下包含巢狀頁面路由。
  • <Route index>:定義 / 路徑的預設頁面為 Home
  • <Route path="*">:匹配所有未定義的網址,用於顯示 404 頁面。

建立頁面元件

Layout.js(共享頁面結構)

import { Outlet, Link } from 'react-router-dom';

const Layout = () => {
return (
<>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/blogs">Blogs</Link>
</li>
<li>
<Link to="/contact">Contact</Link>
</li>
</ul>
</nav>

<Outlet />
</>
);
};

export default Layout;
  • 使用 <Link> 元素建立頁面間的連結。
  • <Outlet> 負責渲染目前選中的頁面內容。

Home.js

const Home = () => {
return <h1>Home</h1>;
};

export default Home;

Blogs.js

const Blogs = () => {
return <h1>Blog Articles</h1>;
};

export default Blogs;

Contact.js

const Contact = () => {
return <h1>Contact Me</h1>;
};

export default Contact;

NoPage.js(404 頁面)

const NoPage = () => {
return <h1>404</h1>;
};

export default NoPage;

總結

透過 React Router,我們可以很輕鬆地為 React 應用程式建立一個多頁面的瀏覽體驗。本篇教學展示了如何安裝 React Router、建立路由結構、撰寫頁面元件,並結合 <Outlet><Link> 實現共用頁面框架與路由切換。這只是入門,React Router v6 還支援更多進階功能,例如動態路由、路由守衛、路由參數等,適合進一步探索使用。

參考文件

  1. React Custom Hooks
  2. React router 官方網站

React 表單入門教學 | w3schools 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

在網頁開發中,表單(Forms)是使用者與網站互動最常見的方式之一。透過表單,我們可以讓使用者輸入資料、提交查詢、填寫訂單等。而在 React 中,表單不再只是簡單的 HTML 元素堆疊,而是成為受控元件(controlled components)的一部分,由 React 元件的 state 負責管理輸入值與提交行為。

本篇教學將帶你一步一步掌握如何在 React 中建立表單、處理輸入變更、提交資料,並涵蓋文字輸入框、多個欄位、Textarea 與 Select 的特殊處理方式,幫助你更靈活地控制資料流程與使用者體驗。


重點摘要

  • 在 React 中,表單輸入值由 component state 管理,稱為「受控元件」。
  • 使用 useState hook 來追蹤每個欄位的變化。
  • 使用 onChange 事件處理輸入值的即時更新。
  • 使用 onSubmit 處理表單送出行為,並透過 event.preventDefault() 阻止預設重新整理頁面的行為。
  • 多個欄位可透過 name 屬性與通用的 handleChange 事件處理函式管理。
  • textareaselect 元素在 React 中透過 value 屬性控制初始與變更的值。

實際範例與說明

一、建立簡單表單

最基本的 React 表單可以像這樣寫:

function MyForm() {
return (
<form>
<label>
Enter your name:
<input type="text" />
</label>
</form>
);
}

雖然這段程式碼可以運作,但在送出表單時會導致頁面刷新。這不是 React 推薦的處理方式。


二、控制輸入欄位(Controlled Components)

我們希望讓 React 完全掌控輸入欄位的狀態,因此需透過 useState 控制值,並在 onChange 事件中更新:

import { useState } from 'react';

function MyForm() {
const [name, setName] = useState('');

return (
<form>
<label>
Enter your name:
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
</label>
</form>
);
}

三、處理表單提交

若想處理送出資料而非重新整理頁面,需使用 onSubmit 並加上 preventDefault()

import { useState } from 'react';

function MyForm() {
const [name, setName] = useState('');

const handleSubmit = (event) => {
event.preventDefault();
alert(`您輸入的名字是:${name}`);
};

return (
<form onSubmit={handleSubmit}>
<label>
Enter your name:
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
</label>
<input type="submit" />
</form>
);
}

四、多個輸入欄位的管理

當表單中有多個欄位時,使用一個 inputs 物件來集中管理會更加方便:

import { useState } from 'react';

function MyForm() {
const [inputs, setInputs] = useState({});

const handleChange = (event) => {
const name = event.target.name;
const value = event.target.value;
setInputs((values) => ({ ...values, [name]: value }));
};

const handleSubmit = (event) => {
event.preventDefault();
alert(`使用者輸入資料:${JSON.stringify(inputs)}`);
};

return (
<form onSubmit={handleSubmit}>
<label>
Enter your name:
<input type="text" name="username" value={inputs.username || ''} onChange={handleChange} />
</label>
<label>
Enter your age:
<input type="number" name="age" value={inputs.age || ''} onChange={handleChange} />
</label>
<input type="submit" />
</form>
);
}

五、Textarea 的處理方式

在 HTML 中 <textarea> 的值寫在標籤中,但在 React 中,需改為用 value 屬性控制:

import { useState } from 'react';

function MyForm() {
const [textarea, setTextarea] = useState('這裡是預設文字');

const handleChange = (event) => {
setTextarea(event.target.value);
};

return (
<form>
<textarea value={textarea} onChange={handleChange} />
</form>
);
}

六、Select 下拉選單的處理方式

同樣地,<select> 元素的選擇值也應由 value 屬性控制:

import { useState } from 'react';

function MyForm() {
const [myCar, setMyCar] = useState('Volvo');

const handleChange = (event) => {
setMyCar(event.target.value);
};

return (
<form>
<select value={myCar} onChange={handleChange}>
<option value="Ford">Ford</option>
<option value="Volvo">Volvo</option>
<option value="Fiat">Fiat</option>
</select>
</form>
);
}

總結

React 提供一種結構化且一致的方式來處理表單資料,透過 Hook 與事件處理,可以讓應用程式中的資料流更容易掌控與維護。只要掌握好 useStateonChangeonSubmit 等基本技巧,就能在 React 中打造功能完整且具有互動性的表單介面,提升整體使用者體驗與應用穩定性。未來若進一步搭配表單驗證函式庫(如 Formik 或 React Hook Form),可以更加有效率地管理大型與複雜表單邏輯。

參考文件

  1. React Custom Hooks

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

· 閱讀時間約 2 分鐘
kdchang

前言

React 是一個用於建立 UI 組件的 JavaScript 函式庫,而 JSX 則是 React 中的重要語法擴充。前一章我們已學會如何使用 JSX 編寫 React 介面,本文將進一步說明 React 元件(Components)、props、事件處理(Events)、條件渲染(Conditional Rendering)與列表渲染(Lists)的基本觀念與應用,協助讀者掌握建立互動式介面的核心技巧。

渲染列表與使用 key

基本列表渲染:

function Car(props) {
return <li>I am a {props.brand}</li>;
}

function Garage() {
const cars = ['Ford', 'BMW', 'Audi'];
return (
<>
<h1>Who lives in my garage?</h1>
<ul>
{cars.map((car) => (
<Car brand={car} />
))}
</ul>
</>
);
}

加上 key 改寫版本:

function Car(props) {
return <li>I am a {props.brand}</li>;
}

function Garage() {
const cars = [
{ id: 1, brand: 'Ford' },
{ id: 2, brand: 'BMW' },
{ id: 3, brand: 'Audi' },
];
return (
<>
<h1>Who lives in my garage?</h1>
<ul>
{cars.map((car) => (
<Car key={car.id} brand={car.brand} />
))}
</ul>
</>
);
}

結論 React 提供了彈性而強大的組件機制,透過 props 傳遞資料、事件處理強化互動、條件與列表渲染控制顯示邏輯,讓開發者可以有效建立模組化與資料驅動的使用者介面。熟悉這些基本觀念,將為深入理解 React 的狀態管理與 hooks 打下堅實基礎。

參考文件

  1. React Custom Hooks

React 條件渲染入門教學 | w3schools 學習筆記

· 閱讀時間約 2 分鐘
kdchang

前言

React 是一個用於建立 UI 組件的 JavaScript 函式庫,而 JSX 則是 React 中的重要語法擴充。前一章我們已學會如何使用 JSX 編寫 React 介面,本文將進一步說明 React 元件(Components)、props 與事件(Events)的基本觀念與應用,並介紹如何透過函式元件建立互動性的使用者介面,進而引入條件渲染的方式,讓介面能根據資料狀態動態改變內容。

重點摘要

  • React 元件就像函式,會回傳 HTML 元素
  • 元件是可獨立、可重複使用的程式區塊
  • 元件名稱需以大寫開頭
  • props 是元件接收的參數,用來傳遞資料
  • props 是唯讀的,不能在元件內部直接修改
  • 事件處理使用 camelCase 並以大括號包覆事件處理函式
  • 可使用箭頭函式傳遞參數至事件處理器
  • 可透過 if、三元運算子、邏輯運算子 && 實現條件渲染

React 條件渲染

React 提供多種條件渲染的方式,以下為三種常見範例:

  • 使用 if 陳述式:
function MadeGoal() {
return <h1>Goal!</h1>;
}

function MissedGoal() {
return <h1>MISSED!</h1>;
}

function Goal(props) {
const isGoal = props.isGoal;
if (isGoal) {
return <MadeGoal />;
}
return <MissedGoal />;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Goal isGoal={true} />);
  • 使用 && 邏輯運算子:
function Garage(props) {
const cars = props.cars;
return (
<>
<h1>Garage</h1>
{cars.length > 0 && <h2>You have {cars.length} cars in your garage.</h2>}
</>
);
}

const cars = ['Ford', 'BMW', 'Audi'];
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Garage cars={cars} />);
  • 使用三元運算子:
function Goal(props) {
const isGoal = props.isGoal;
return <>{isGoal ? <MadeGoal /> : <MissedGoal />}</>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Goal isGoal={false} />);

總結

React 元件是建構 UI 的基本單位,透過 props 傳遞資料與事件處理建立互動,並透過條件渲染控制顯示邏輯。這些基礎觀念為日後深入學習狀態管理、Hooks 與表單處理等主題奠定堅實基礎。

參考文件

  1. React Custom Hooks