Hooks基础-------useReducer基本用法

1、什么是reducer?

reducer是一个函数(state, action) => newState:接收当前应用的state和触发的动作action,计算并返回最新的state

2、useReducer

const [state, dispatch] = useReducer(reducer, initState, init);

useReducer接收三个参数:

第一个参数:reducer。

第二个参数:初始化的state。如果没有第三个参数,则state默认是传入的值,返回值为最新的state和dispatch函数(用来触发reducer函数,计算对应的state)。

第三个参数:如果有这个参数,则对初始值state做一个更新(可以没有)

按照官方的说法:对于复杂的state操作逻辑,嵌套的state的对象,推荐使用useReducer。

3、案例

3.1 利用useReducer改写加减操作

原例:

function Example() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>you click {count} times</p>
      <button onClick={() => setCount(count + 1)}>click me to +</button>
      <button onClick={() => setCount(count - 1)}>click me to -</button>
    </div>
  );
}

改写后

import React, { useReducer } from "react";
​
function reducer(state, action) {
  switch (action.type) {
    case "reset":
      return { count: action.payload };
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}
​
function init(initialCountState) {
  return { count: initialCountState.count + 1 };
}
​
function Counter({ initialCount }) {
  const [state, dispatch] = useReducer(
    reducer,
    initialCount, //通过参数传递来的默认值,如果没有第三个参数,则state默认是1
    init //如果有这个参数,则对初始值state做一个更新
  );
  return (
    <div>
      Count:{state.count}
      <button
        onClick={() => dispatch({ type: "reset", payload: initialCount.count })}
      >
        reset
      </button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </div>
  );
}
​
function Example() {
  return <Counter initialCount={{ count: 1 }} />;
}
​
export default class App extends React.Component {
  render() {
    return (
      <div>
        <Example />
        <hr />
      </div>
    );
  }
}
​

发现更难了。。原因很简单,因为加减这种逻辑很简单,没有必要使用useReducer

3.2 登录操作

利用useState方法编写

import React, { useState } from "react";
​
function Example() {
  const [name, setName] = useState(""); // 用户名
  const [pwd, setPwd] = useState(""); // 密码
  const [isLoading, setIsLoading] = useState(false); // 是否展示loading,发送请求中
  const [error, setError] = useState(""); // 错误信息
  const [isLoggedIn, setIsLoggedIn] = useState(false); // 是否登录
​
  const login = (name, pwd) => {
    setIsLoading(true);
    if (name === "123" && pwd === "123") {
      setError("");
      setIsLoggedIn(true);
      setIsLoading(false);
    } else {
      setError("error");
      setName("");
      setPwd("");
      setIsLoggedIn(false);
      setIsLoading(false);
    }
  };
  return (
    //  返回页面JSX Element
    <div>
      用户名:
      <input
        type="text"
        onChange={(e) => setName(e.target.value)}
        value={name}
      />
      <br />
      密码:
      <input type="text" onChange={(e) => setPwd(e.target.value)} value={pwd} />
      <br />
      <button onClick={() => login(name, pwd)} disabled={isLoading}>
        登录
      </button>
      <br />
      {isLoggedIn ? "登录成功" : error}
    </div>
  );
}
​
export default class App extends React.Component {
  render() {
    return (
      <div>
        <Example />
        <hr />
      </div>
    );
  }
}

上面Demo我们定义了5个state来描述页面的状态,在login函数中当登录成功、失败时进行了一系列复杂的state设置。可以想象随着需求越来越复杂更多的state加入到页面,更多的setState分散在各处,很容易设置错误或者遗漏,维护这样的老代码更是一个噩梦。

利用useReducer编写

import React, { useReducer } from "react";
​
const initState = {
  name: "",
  pwd: "",
  isLoading: false,
  error: "",
  isLoggedIn: false,
};
function loginReducer(state, action) {
  switch (action.type) {
    case "name":
      return {
        ...state,
        name: action.payload.name,
      };
    case "pwd":
      return {
        ...state,
        pwd: action.payload.pwd,
      };
    case "login":
      return {
        ...state,
        isLoading: true,
        error: "",
      };
    case "success":
      return {
        ...state,
        isLoggedIn: true,
        isLoading: false,
        error: "",
      };
    case "error":
      return {
        ...state,
        error: action.payload.error,
        name: "",
        pwd: "",
        isLoading: false,
        isLoggedIn: false,
      };
    default:
      return state;
  }
}
function Example() {
  const [state, dispatch] = useReducer(loginReducer, initState);
  const { name, pwd, isLoading, error, isLoggedIn } = state;
  const login = (name, pwd) => {
    dispatch({ type: "login" });
    if (name === "123" && pwd === "123") {
      dispatch({ type: "success" });
    } else {
      dispatch({
        type: "error",
        payload: { error: "登录失败" },
      });
    }
  };
  return (
    <div>
      用户名:
      <input
        type="text"
        onChange={(e) => {
          dispatch({
            type: "name",
            payload: { name: e.target.value },
          });
        }}
        value={name}
      />
      <br />
      密码:
      <input
        type="text"
        onChange={(e) => {
          dispatch({
            type: "pwd",
            payload: { pwd: e.target.value },
          });
        }}
        value={pwd}
      />
      <br />
      <button onClick={() => login(name, pwd)} disabled={isLoading}>
        登录
      </button>
      <br />
      {isLoggedIn ? "登录成功" : error}
    </div>
  );
}
​
export default class App extends React.Component {
  render() {
    return (
      <div>
        <Example />
        <hr />
      </div>
    );
  }
}
​

代码着实还是变长了,但也有好处

1、更好的可读性,我们也能更清晰的了解state的变化逻辑。

2、所有的state处理都集中到了一起,使得我们对state的变化更有掌控力,同时也更容易复用state逻辑变化代码

useReducer可以让我们将whathow分开。比如点击了登录按钮,我们要做的就是发起登陆操作dispatch({ type: 'login' }),点击退出按钮就发起退出操作dispatch({ type: 'logout' }),所有和how相关的代码都在reducer中维护,组件中只需要思考What,让我们的代码可以像用户的行为一样,更加清晰。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值