useReducer
是 React 提供的 Hooks 之一,用於管理狀態和處理與狀態相關的操作。
它與 useState
不同,useState
主要用於管理單一值的狀態,而 useReducer
更適用於複雜的狀態邏輯,例如物件或陣列。
我們將創建一個計數器應用程式,並使用 useReducer
來管理計數器的狀態。
count
和 step
。const initialState = {
count: 0,
step: 1
};
const initialState = {
count: 0,
step: 1
};
function Counter() {
return (
<div className="counter">
<div>
<input
type="range"
min="0"
max="10"
/>
<span>{step}</span>
</div>
<div>
<button>-</button>
<input />
<button>+</button>
</div>
<div>
<button>Reset</button>
</div>
</div>
);
}
useReducer
,useReducer
這邊傳入兩個參數,第一個參數 reducer
是我們稍後要處理狀態邏輯的一個函式,第二個參數 initialState
是我們狀態的初始值。const initialState = {
count: 0,
step: 1
};
function Counter() {
useReducer(reducer, initialState);
return (
...
);
}
useReducer
和 useState
一樣會返回包含兩個值的陣列,所以在這邊一樣使用陣列解構取出,並將其命名為 state
和 dispatch
,state
將會是 count
和 step
的物件資料,因此我們還可以從 state
再解構出我們的 count
和 step
狀態。const initialState = {
count: 0,
step: 1
};
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
return (
...
);
}
count
和 step
綁定到 input 元素上面。const initialState = {
count: 0,
step: 1
};
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
return (
<div className="counter">
<div>
<input
type="range"
min="0"
max="10"
value={step}
/>
<span>{step}</span>
</div>
<div>
<button>-</button>
<input value={count} />
<button>+</button>
</div>
<div>
<button>Reset</button>
</div>
</div>
);
}
const initialState = {
count: 0,
step: 1
};
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
function defineCount() {};
function defineStep() {};
function handleDecrement() {};
function handleIncrement() {};
function handleReset() {};
return (
<div className="counter">
<div>
<input
type="range"
min="0"
max="10"
value={step}
onChange={defineStep}
/>
<span>{step}</span>
</div>
<div>
<button onClick={handleDecrement}>-</button>
<input value={count} onChange={defineCount} />
<button onClick={handleIncrement}>+</button>
</div>
<div>
<button onClick={handleReset}>Reset</button>
</div>
</div>
);
}
dispatch
這個函式去觸發,並且我們可以傳入一個物件去包含我們所需要的資料。const initialState = {
count: 0,
step: 1
};
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
function defineCount(e) {
dispatch({
type: "setCount",
payload: Number(e.target.value)
});
};
function defineStep(e) {
dispatch({
type: "setStep",
payload: Number(e.target.value)
});
};
function handleDecrement() {
dispatch({ type: "decrement" });
};
function handleIncrement() {
dispatch({ type: "increment" });
};
function handleReset() {
dispatch({ type: "reset" });
};
return (
<div className="counter">
<div>
<input
type="range"
min="0"
max="10"
value={step}
onChange={defineStep}
/>
<span>{step}</span>
</div>
<div>
<button onClick={handleDecrement}>-</button>
<input value={count} onChange={defineCount} />
<button onClick={handleIncrement}>+</button>
</div>
<div>
<button onClick={handleReset}>Reset</button>
</div>
</div>
);
}
dispatch
函式後,傳入的值將會在 reducer
函式去接收。const initialState = {
count: 0,
step: 1
};
function reducer(state, action) {}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
function defineCount(e) {
dispatch({
type: "setCount",
payload: Number(e.target.value)
});
};
function defineStep(e) {
dispatch({
type: "setStep",
payload: Number(e.target.value)
});
};
function handleDecrement() {
dispatch({ type: "decrement" });
};
function handleIncrement() {
dispatch({ type: "increment" });
};
function handleReset() {
dispatch({ type: "reset" });
};
return (
...
);
}
reducer
函式內部,我們可以使用 switch
來判斷 dispatch
傳入的 type
屬性,再來決定要執行哪些操作。const initialState = {
count: 0,
step: 1
};
// state 是目前的狀態
// action 是我們下方 dispatch 傳入的物件資料
function reducer(state, action) {
switch (action.type) {
case "decrement":
return {
...state,
count: state.count - state.step
};
case "increment":
return {
...state,
count: state.count + state.step
};
case "setCount":
return {
...state,
count: action.payload
};
case "setStep":
return {
...state,
step: action.payload
};
case "reset":
return initialState;
default:
throw new Error("錯誤的 type");
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
function defineCount(e) {
dispatch({
type: "setCount",
payload: Number(e.target.value)
});
};
function defineStep(e) {
dispatch({
type: "setStep",
payload: Number(e.target.value)
});
};
function handleDecrement() {
dispatch({ type: "decrement" });
};
function handleIncrement() {
dispatch({ type: "increment" });
};
function handleReset() {
dispatch({ type: "reset" });
};
return (
<div className="counter">
<div>
<input
type="range"
min="0"
max="10"
value={step}
onChange={defineStep}
/>
<span>{step}</span>
</div>
<div>
<button onClick={handleDecrement}>-</button>
<input value={count} onChange={defineCount} />
<button onClick={handleIncrement}>+</button>
</div>
<div>
<button onClick={handleReset}>Reset</button>
</div>
</div>
);
}
useReducer
主要是透過 dispatch
函式來跟 reducer
函式做溝通,在邏輯上會比 useState
複雜一些,但假如我們的狀態是會相互關聯的,就可以嘗試使用 useReducer
來調整程式碼架構。
useReducer
用於處理複雜的狀態邏輯。通過定義 reducer
函式並使用 dispatch
函式,我們可以有效地管理應用程式的狀態和操作。