useReducer介紹及實際案例
useReducer
是 React 提供的一個 Hook 函式,主要是用來處理 複雜或多步驟的狀態邏輯,特別是在一個 state 會受到多種 action 操作時,比 useState
更好管理。
一句話說明:
useReducer
就像是你自己在 React 裡開了一間「迷你版 Redux」,把狀態更新邏輯集中處理,更有組織性!
基本語法:
const [state, dispatch] = useReducer(reducer, initialState);
- state
:當前狀態的值
- dispatch(action)
:發送一個動作 (action),來觸發對應的狀態更新
- reducer(state, action)
:接收當前狀態與動作,並根據動作內容回傳新的狀態
- initialState
:初始狀態的值
實際案例一:簡易的計數器(Counter)
這個例子中,點按按鈕可以增加、減少、重設計數。
import React, { useReducer } from "react";
// 定義 reducer 函式
function reducer(state: number, action: { type: string }) {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
case "reset":
return 0;
default:
return state;
}
}
export default function Counter() {
// 使用 useReducer,初始值為 0
const [count, dispatch] = useReducer(reducer, 0);
return (
<div>
<h2>目前數字:{count}</h2>
<button onClick={() => dispatch({ type: "increment" })}>+1</button>
<button onClick={() => dispatch({ type: "decrement" })}>-1</button>
<button onClick={() => dispatch({ type: "reset" })}>重設</button>
</div>
);
}
實際案例二:Todo 待辦清單管理
import React, { useReducer, useState } from "react";
type Todo = {
id: number,
text: string,
completed: boolean,
};
type Action =
| { type: "add", text: string }
| { type: "toggle", id: number }
| { type: "delete", id: number };
// Reducer 函式
function todoReducer(state: Todo[], action: Action): Todo[] {
switch (action.type) {
case "add":
return [
...state,
{ id: Date.now(), text: action.text, completed: false },
];
case "toggle":
return state.map((todo) =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
case "delete":
return state.filter((todo) => todo.id !== action.id);
default:
return state;
}
}
export default function TodoApp() {
const [todos, dispatch] = useReducer(todoReducer, []);
const [text, setText] = useState("");
return (
<div>
<h2> Todo 清單</h2>
<input
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="輸入待辦事項"
/>
<button
onClick={() => {
dispatch({ type: "add", text });
setText("");
}}
>
新增
</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span
onClick={() => dispatch({ type: "toggle", id: todo.id })}
style={{
textDecoration: todo.completed ? "line-through" : "none",
cursor: "pointer",
}}
>
{todo.text}
</span>
<button onClick={() => dispatch({ type: "delete", id: todo.id })}>
刪除
</button>
</li>
))}
</ul>
</div>
);
}
適合用 useReducer
的時機
-
狀態邏輯複雜(例如有多種
action
) -
多個 state 彼此之間有關聯性
-
想要讓程式碼更模組化、可預測