Skip to main content

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 彼此之間有關聯性

  • 想要讓程式碼更模組化、可預測