7.react useReducer使用与常见问题

useReducer函数

1. useState的替代方案.接收一个(state, action)=>newState的reducer,
并返回当前的state以及与其配套的dispatch方法

2. 在某些场景下,useReducer会比useState更加适用,例如state逻辑较为复杂,
且**包含多个子值**,或者下一个state依赖于之前的state等

清楚useReducer场景?
与useState区别?
不足之处,只能处理同步
如何实现异步,提供了两个案例?

1. 用useState做登录

一组响应式数据有关联关系,可以做成一个整体,使用useReducer将其作为一个整体实现

html 复制代码
<body>
  <div id="app"></div>
  <script type="text/babel">
    let app = document.querySelector('#app');
    let root = ReactDOM.createRoot(app);
    let { useState } = React;

    // 用useState做登录
    // >  一组响应式数据有关联关系,可以做成一个整体,使用useReducer将其作为一个整体实现
    let Welcome = (props) => {  
      const [ isLogin, setLogin ] = useState(true);
      const [ isLogout, setLogout ] = useState(false);
      const handleLogin= () => {
        setLogin(true);
        setLogout(false);
      }

      const handleLogout= () => {
        setLogout(true);
        setLogin(false);
      }
      return (
        <div>
         {
          isLogin?
          <button onClick={handleLogout}>登出</button>:
          <button onClick={handleLogin}>登录</button>
         }
        </div>
      );
    }
    
    let element = (
      <Welcome />
    );
    root.render(element);
  </script>
</body>

2. 改为useReducer

html 复制代码
<body>
  <div id="app"></div>
  <script type="text/babel">
    /* 
    useReducer改写
    */

    let app = document.querySelector('#app');
    let root = ReactDOM.createRoot(app);
    let { useReducer } = React;


    let loginState = {
      isLogin: true,
      isLogout: false
    }

    // 不足: 处理同步action
    let loginReducer = (state, action) => {
      switch (action.type) {
        case 'login':
          return { isLogin: true, isLogout: false }
        case 'logout':
          return { isLogin: false, isLogout: true }
        default:
          throw new Error()
      }
    }
    // 用useReducer做登录
    // > 根据类型,决定不同的state处理变化
    let Welcome = (props) => {
      const [state, loginDispatch] = useReducer(loginReducer, loginState);
      const handleLogin = () => {
        loginDispatch({ type: 'login' })
      }

      const handleLogout = () => {
        loginDispatch({ type: 'logout' })
        // loginDispatch({ type: 'logout' ,payload:''})
      }
      return (
        <div>
          {
            state.isLogin ?
              <button onClick={handleLogout}>登出</button> :
              <button onClick={handleLogin}>登录</button>
          }
        </div>
      );
    }

    let element = (
      <Welcome />
    );
    root.render(element);
  </script>
</body>

不足

useReduer只处理同步请求,对异步请求如何处理?
https://zhuanlan.zhihu.com/p/114367502

3.1 异步封装

js 复制代码
组件页面
const init = { dataList:[] };//初始化dataState
 
const [state,dispatch] = useReducer(reducer,init);
 
useEffect(() => {
    //发送网络请求
    axios.get("/user?ID=123").then(res => {
        dispatch({
            type:ACTION_TYPE.GETDATA,
            payload:res.data //后端返回的数据
        })
    })
},[]);
 
//使用 state.dataList 渲染页面
js 复制代码
在reducer页面

function reducer(state,action){
    switch(action.type){
        case "getData":
            return { //根据需求对数据做出操作,这里将返回的数据与初始化的数据合并
                ...state,
                dataList:action.payload 
            };
}    
 
export default reducer;

3.2 异步封装

初始化直接执行获取数据

js 复制代码
import React, { useEffect, useState, useReducer } from "react";
import ReactDom from "react-dom";
import $ from "jquery";

const useProduct = () => {
  const [data, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case "a":
        return action.value;
      default:
        return [];
    }
  }, []);

  useEffect(() => {
    $.ajax({
      url: "http://suggest.taobao.com/sug?code=utf-8&q=袜子",
      dataType: "jsonp",
      jsonp: "callback",
      success: (data) => {
        dispatch({
          type: 'a',
          value: data.result
        });
      },
      error: data => dispatch({type: 'error', msg: data})
    });
  }, []);

  return data;
};

const Index = () => {
  const data = useProduct();

  return <>{data.length}</>;
};

ReactDom.render(<Index />, document.getElementById("root"));

官网:
1. https://zh-hans.legacy.reactjs.org/docs/hooks-reference.html#usereducer

相关推荐
小马哥编程27 分钟前
Function.prototype和Object.prototype 的区别
javascript
小白学前端66627 分钟前
React Router 深入指南:从入门到进阶
前端·react.js·react
王小王和他的小伙伴1 小时前
解决 vue3 中 echarts图表在el-dialog中显示问题
javascript·vue.js·echarts
学前端的小朱1 小时前
处理字体图标、js、html及其他资源
开发语言·javascript·webpack·html·打包工具
outstanding木槿1 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08212 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
摇光932 小时前
js高阶-async与事件循环
开发语言·javascript·事件循环·宏任务·微任务
等一场春雨2 小时前
springboot 3 websocket react 系统提示,选手实时数据更新监控
spring boot·websocket·react.js
风无雨2 小时前
react杂乱笔记(一)
前端·笔记·react.js
胡西风_foxww2 小时前
【ES6复习笔记】Class类(15)
javascript·笔记·es6·继承··class·静态成员