【React全解6】useReducer的使用详解和代替Redux

23 篇文章 0 订阅
7 篇文章 3 订阅

目录

  • 前言
  • useReducer
  • 使用useReducer写一个表单提交的案例
  • 使用useReducer代替Redux

一、前言

前面已经介绍了useState 的详细用法,我们可以在函数组件和类组件中使用 useState 来创建变量和对象。使得页面能够及时的更新 UI 等等。接下来介绍一个 useState 的复杂版本–useReducer

二、useReducer

useReducer 是 useState 的升级版本,用来践行 Flux/Redux 的思想

它主要有两个参数,一个读接口 state,一个写接口 dispatch

要自己先定义好 state 状态量和 setState 的一些函数 API

参数列表:useReducer(dispatch,state,init)

1、使用 useReducer

在页面中显示 n 的值,且按下按钮后会触发响应的操作使 n 值发生变化。其中的操作分别是使 n+1,n+2,nx2。

const initialState = {
  n: 0,
};
const reducer = (state, action) => {
  if (action.type === "add") {
    /* 规则与useState一样必须返回新的对象,不然变量值不会改变 */
    return { n: state.n + action.number };
  } else if (action.type === "multi") {
    return { n: state.n * action.number };
  } else {
    throw new Error("unknown type!");
  }
};
/* 在函数组件中使用useReducer */
const App = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const onclick1 = () => {
    dispatch({ type: "add", number: 1 });
  };
  const onclick2 = () => {
    dispatch({ type: "add", number: 2 });
  };
  const onclick3 = () => {
    dispatch({ type: "multi", number: 2 });
  };
  return (
    <div className="App">
      <h1>n:{state.n}</h1>
      <button onClick={onclick1}>+1</button>
      <button onClick={onclick2}>+2</button>
      <button onClick={onclick3}>x2</button>
    </div>
  );
};
ReactDOM.render(<App />, document.getElementById("root"));
  • 效果展示

在对+1、+2、x2 按钮一番按键后,改变了页面中的 n 值。

在这里插入图片描述

2、总结

用法与 useState 类似,从 useReducer 中得到读接口 state,写接口 dispatch。最后操作时传参给 dispatch 写接口。操作灵活多变,比 useState 好处就是能聚集所有的操作和各种状态量。着重理解这几行代码,读懂。

useReducer 算是 useState 的复杂版

使用 useReducer 分以下步骤:

  • 创建初始值的状态initialState
  • 创建所有对状态的操作reducer(state,action)
  • 传给useReducer,得到读和写的接口
  • 调用写({'type':'操作类型'})

三、使用 useReducer 写一个表单提交

写一个简单的表单,包含姓名,年龄,民族等信息。在下方显示输入表单的值的动态变化

const initialState = {
  name: "",
  age: 18,
  nationality: "汉族",
};
const reducer = (state, action) => {
  switch (action.type) {
    case "patch":
      return { ...state, ...action.formData };
    case "reset":
      return initialState;
    default:
      throw new Error("unknown type!");
  }
};
/* 在函数组件中使用useReducer */
const App = () => {
  const [formData, dispatch] = useReducer(reducer, initialState);
  const onSubmit = () => {
    alert("你点击了提交按钮");
  };
  const onReset = () => {
    dispatch({ type: "reset" });
  };
  return (
    <form onSubmit={onSubmit} onReset={onReset}>
      <div>
        <label>
          姓名
          <input
            type="text"
            value={formData.name}
            onChange={(e) => {
              dispatch({ type: "patch", formData: { name: e.target.value } });
            }}
          />
        </label>
      </div>
      <div>
        <label>
          年龄
          <input
            type="number"
            value={formData.age}
            onChange={(e) => {
              dispatch({ type: "patch", formData: { name: e.target.value } });
            }}
          />
        </label>
      </div>
      <div>
        <label>
          民族
          <input
            type="text"
            value={formData.nationality}
            onChange={(e) => {
              dispatch({
                type: "patch",
                formData: { nationality: e.target.value },
              });
            }}
          />
        </label>
      </div>
      <div>
        <button type="submit">提交</button>
        <button type="reset">重置</button>
      </div>
      <hr />
      {JSON.stringify(formData)}
    </form>
  );
};
ReactDOM.render(<App />, document.getElementById("root"));
  • 效果展示

我随意在输入框中输入一些东西,下面会及时的更新显示出来的输入的数据

在这里插入图片描述

四、使用 useReducer 代替 Redux

使用 createContext/useContext 模拟 Redux 的全局数据状态管理的作用域,useReducer 来表示全局数据状态管理中的所有读写操作。

在创建的上下文对象中能够及时更新数据,就类似于一个局部的 Redux。在以下代码中,案例:我将模拟一个 state 有三个变量 n,m,p。一个组件更新,其他组件的值也会连带着更新。

1、案例代码
const store = {
  n: 0,
  m: 0,
  p: 0,
};
const reducer = (state, action) => {
  switch (action.type) {
    case "setN":
      return { ...state, n: state.n + action.number };
    case "setM":
      return { ...state, m: state.m + action.number };
    case "setP":
      return { ...state, p: state.p + action.number };
    default:
      throw new Error("unknown type!");
  }
};
/* 创建上下文对象--模拟一个Redux的作用域 */
const Context = React.createContext(null);
const App = () => {
  const [state, dispatch] = React.useReducer(reducer, store);
  return (
    <Context.Provider value={{ state, dispatch }}>
      <N />
      <M />
      <P />
    </Context.Provider>
  );
};
const N = () => {
  const { state, dispatch } = React.useContext(Context);
  const addClick = () => {
    dispatch({ type: "setN", number: 1 });
  };
  return (
    <div>
      <h1>N组件</h1>
      <div>n:{state.n}</div>
      <div>m:{state.m}</div>
      <div>p:{state.p}</div>
      <button onClick={addClick}>+1</button>
    </div>
  );
};
const M = () => {
  const { state, dispatch } = React.useContext(Context);
  const addClick = () => {
    dispatch({ type: "setM", number: 2 });
  };
  return (
    <div>
      <h1>M组件</h1>
      <div>n:{state.n}</div>
      <div>m:{state.m}</div>
      <div>p:{state.p}</div>
      <button onClick={addClick}>+2</button>
    </div>
  );
};
const P = () => {
  const { state, dispatch } = React.useContext(Context);
  const addClick = () => {
    dispatch({ type: "setP", number: 3 });
  };
  return (
    <div>
      <h1>P组件</h1>
      <div>n:{state.n}</div>
      <div>m:{state.m}</div>
      <div>p:{state.p}</div>
      <button onClick={addClick}>+3</button>
    </div>
  );
};
ReactDOM.render(<App />, document.getElementById("root"));
  • 效果展示

在一番对 n,m,p 数据的操作后,所有组件的值都变化了更新

在这里插入图片描述

2、使用 reducer 总结
  • createContext/useContext 来作为一个模拟 Redux 的作用域
  • useReducer 作为这个作用域中的对数据的所有读写操作
  • 若 state 数据中有多个值或对象,要先使用...state拷贝原先的数据,在覆写要修改的数据。原因:【React 全解 1 state&setState
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值