提供了操纵多个状态的能力,如果状态是单个的,可以是 useState 的替代。
语法:

const [state, dispatch] = useReducer(reducer, initialState)
const [state, dispatch] = useReducer(reducer, initialState, initFunction) 
// 惰性地创建初始 state, 需要将 init 函数作为 useReducer 的第三个参数传入,这样初始 state 将被设置为 init(initialState)
// 或者
const [state, dispatch] = useReducer(reducer, undefined, initFunction)

示例:

import React, {useReducer, useEffect} from "react";
import ReactDOM from "react-dom";

interface State {
  count: number;
  step: number
}

interface Action {
  type: string;
  payload?: any;
}

const initialState: State = {
  count: 0,
  step: 1,
};

const reducer = (state: State, action: Action) => {
  const {count, step} = state;
  if (action.type === 'tick') {
    return {count: count + step, step};
  } else if (action.type === 'step') {
    return {count, step: action.payload};
  } else {
    throw new Error();
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const {count, step} = state;

  useEffect(() => {
    const id = setInterval(() => {
      dispatch({type: 'tick'});
    }, 1000);
    return () => clearInterval(id);
  }, [dispatch]);

  return (
    <div style={{
      width: '200px',
      margin: '100px auto 0 auto',
      textAlign: 'center',
      border: '1px solid #DDD',
      borderRadius: '4px',
    }}>
      <h1 style={{margin: '10px 0'}}>
        {count}
      </h1>
      <input
        style={{
          marginBottom: '10px',
          border: '1px solid #DDD',
          height: '32px',
          lineHeight: '32px',
          borderRadius: '4px',
        }}
        value={step}
        onChange={e => {
          dispatch({
            type: 'step',
            payload: Number(e.target.value)
          });
        }}
      />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Counter/>, rootElement);