這個 hook 可以讓我們用類似 redux 用 reducer、action、dispatch 操作 state。
useReducer 適合較複雜的 state,因為我們可以將狀態的改變統一放在 reducer 去做管理,像 useState 的狀態改變就會分散在不同的函式裡面。
useState 的底層其實是用 useReducer 實踐的
const [state, dispatch] = useReducer(reducer, initialState, initStateFn);
第三個參數要怎麼使用? 這個在 React 官網有提到,撰寫一個會 return 初始化 state 的函式,放到第三個參數,可以避免重新去建立初始 state。
如果把初始化 state 的函式包在 useReducer 第二個參數,會在每次 render 呼叫,所以要避免。
function createInitialState(username) {
// init state
}
function TodoList({ username }) {
const [state, dispatch] = useReducer(reducer, username, createInitialState);
// ...
dispatch 不會隨著 rerender 而重新分配記憶體位置,在作為 props 傳入到 child component 中時也可以不用擔心沒有 useMemo 而造成 re-render 的問題
import React, { useReducer } from "react";
// 初始化 state
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return { count: (state.count = 0) };
default:
return { count: state.count };
}
}
export default function App() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
Count: {state.count}
<br />
<br />
<button onClick={() => dispatch({ type: "increment" })}>Increment</button>
<button onClick={() => dispatch({ type: "decrement" })}>Decrement</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
);
}
本篇範例程式在以下連結: