
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 函式,我們可以有效地管理應用程式的狀態和操作。