useReducer(reducer, initialArg, init?)

useReducer在组件的顶层调用以使用reducer管理state。

import { useReducer } from 'react';


function reducer(state, action) {
  // ...
}


function MyComponent() {
  const [state, dispatch] = useReducer(reducer, { age: 42 });
  // ...

参数

返回值

useReducer返回一个两个值的数组:

  1. 当前state。在第一次渲染期间,它被设置为init(initialArg)or initialArg(如果没有init)。
  2. dispatch函数,将状态更新为不同的值并触发重新渲染。

注意事项

规范

 switch (action.type) {
    case 'incremented_age': {
      return {
        name: state.name,
        age: state.age + 1
        //不建议直接更改状态
      };
    }
         
 switch (action.type) {
    case 'incremented_age': {
      // ✅ Instead, return a new object
      return {
        ...state,
        age: state.age + 1
		//正确姿势
      };

避免对初始状态进行直接计算

初始状态保存一次,下一次渲染时忽略。

function createInitialState(username) {
  // ...
}


function TodoList({ username }) {
  const [state, dispatch] = useReducer(reducer, createInitialState(username));
  // ...

如果按上述代码运行,在每次渲染时调用 createInitialState(username)函数。在创建大型数组或执行大量计算的情况下,效率就会变的很低

为了解决这个问题,将计算过程作为初始化函数传递给useReducer第三个参数:

function createInitialState(username) {
  // ...
}


function TodoList({ username }) {
  const [state, dispatch] = useReducer(reducer, null, createInitialState);
  // ...
}

传递的是函数本身,而不是createInitialState()。初始化后不会重新创建初始状态。

在上面的例子中,createInitialState接受一个username参数。如果不需要任何信息,只需要第三函数的返回值来作为state,可以将null其作为第二个参数传递给useReducer.

useContext()和useReducer()组合代替Redux来管理状态

// reducer
const reducer = (state, action) => {
  switch(action.type) {
    case 'change':
      return action.color
    default:
      return state  
  }
}

/**
 * 创建一个 Color 组件
 * Color 组件包裹的所有组件都可以访问到 value
 */
export const Color = props => {
  const [color, dispatch] = useReducer(reducer, 'blue')
  return (
    <ColorContext.Provider value={{color, dispatch}}>
      {props.children}
    </ColorContext.Provider>
  );
};

意思就是,将useContext()作为穿透作用域的工具,里面传入useReducer()

使用useReducer()来对状态进行初始化和操作管理