美文网首页
react_16Hooks_二(组件中的异步操作)

react_16Hooks_二(组件中的异步操作)

作者: 小话001 | 来源:发表于2022-10-28 10:07 被阅读0次

    在之前简单的案例中,redux中保存的counter是一个本地定义的数据:

    • 我们可以直接通过同步的操作来dispatch action,state就会被立即更新。
    • 但是真实开发中,redux中保存的很多数据可能来自服务器,我们需要进行异步的请求,再将数据保存到redux中。
      之前的逻辑:
      图一缺陷.jpg
      实际上可以做到:
      图二合理.jpg
      按照之前的逻辑完成案例:Home组件中请求数据,About组件中展示数据:
      store/actionCreators.js
    import {  ADD_NUMBER, SUB_NUMBER,INCREMENT,DECREMENT,CHANGE_BANNERS,CHANGE_RECOMMEND} from './constants.js';
    
    // export function addAction(num) {
    //   return {
    //     type: "ADD_NUMBER",
    //     num
    //   }
    // }
    
    // export const addAction = (num) => {
    //   return {
    //     type: "ADD_NUMBER",
    //     num
    //   }
    // }
    
    export const addAction = num => ({
      type: ADD_NUMBER,
      num
    });
    
    export const subAction = num => ({
      type: SUB_NUMBER,
      num
    });
    
    export const incAction = () => ({
      type: INCREMENT
    });
    
    export const decAction = () => ({
      type: DECREMENT
    });
    
    // 轮播图和推荐的action
    export const changeBannersAction = (banners) => ({
      type: CHANGE_BANNERS,
      banners
    });
    
    export const changeRecommendAction = (recommends) => ({
      type: CHANGE_RECOMMEND,
      recommends
    });
    

    store/constants.js

    export const ADD_NUMBER = "ADD_NUMBER";
    export const SUB_NUMBER = "SUB_NUMBER";
    export const INCREMENT = "INCREMENT";
    export const DECREMENT = "DECREMENT";
    
    export const FETCH_HOME_MULTIDATA = "FETCH_HOME_MULTIDATA";
    export const CHANGE_BANNERS = "CHANGE_BANNERS";
    

    store/reducer.js

    import { ADD_NUMBER,SUB_NUMBER,INCREMENT,DECREMENT,CHANGE_BANNERS,CHANGE_RECOMMEND } from "./constants.js";
    
    const defaultState = {
      counter: 0,
      banners: [],
      recommends: [],
    };
    
    function reducer(state = defaultState, action) {
      switch (action.type) {
        case ADD_NUMBER:
          return { ...state, counter: state.counter + action.num };
        case SUB_NUMBER:
          return { ...state, counter: state.counter - action.num };
        case INCREMENT:
          return { ...state, counter: state.counter + 1 };
        case DECREMENT:
          return { ...state, counter: state.counter - 1 };
        case CHANGE_BANNERS:
          return { ...state, banners: action.banners };
        case CHANGE_RECOMMEND:
          return { ...state, recommends: action.recommends };
        default:
          return state;
      }
    }
    
    export default reducer;
    

    pages/home.js获取数据 (只做演示,真正项目一般也不放在这里)

    import React, { PureComponent } from 'react';
    import { connect } from 'react-redux';
    
    import axios from 'axios';
    
    import { incAction, addAction, changeBannersAction,changeRecommendAction } from '../store/actionCreators'
    
    class Home extends PureComponent {
      componentDidMount() {
        axios({
          url: "http://123.207.32.32:8000/home/multidata",
        }).then(res => {
          const data = res.data.data;
          this.props.changeBanners(data.banner.list);
          this.props.changeRecommends(data.recommend.list);
        })
      }
    
      render() {
        return (
          <div>
            <h1>Home</h1>
            <h2>当前计数: {this.props.counter}</h2>
            <button onClick={e => this.props.increment()}>+1</button>
            <button onClick={e => this.props.addNumber(5)}>+5</button>
          </div>
        )
      }
    }
    
    const mapStateToProps = state => ({
      counter: state.counter
    })
    
    const mapDispatchToProps = dispatch => ({
      increment() {
        dispatch(incAction());
      },
      addNumber(num) {
        dispatch(addAction(num));
      },
      changeBanners(banners) {
        dispatch(changeBannersAction(banners));
      },
      changeRecommends(recommends) {
        dispatch(changeRecommendAction(recommends));
      }
    })
    
    export default connect(mapStateToProps, mapDispatchToProps)(Home);
    

    pages/about.js展示数据

    import React from 'react';
    import { connect } from 'react-redux';
    
    import {decAction, subAction } from "../store/actionCreators";
    
    function About(props) {
      console.log("About页面重新渲染了");
      return (
        <div>
          <hr />
          <h1>About</h1>
          {/* <h2>当前计数: {props.counter}</h2> */}
          <button onClick={e => props.decrement()}>-1</button>
          <button onClick={e => props.subNumber(5)}>-5</button>
          <h1>Banner</h1>
          <ul>
            {
              props.banners.map((item, index) => {
                return <li key={item.acm}>{item.title}</li>
              })
            }
          </ul>
          <h1>Recommend</h1>
          <ul>
            {
              props.recommends.map((item, index) => {
                return <li key={item.acm}>{item.title}</li>
              })
            }
          </ul>
        </div>
      )
    }
    
    const mapStateToProps = state => {
      return {
        banners: state.banners,
        recommends: state.recommends
      }
    };
    
    const mapDispatchToProps = dispatch => {
      return {
        decrement: function () {
          dispatch(decAction());
        },
        subNumber: function (num) {
          dispatch(subAction(num))
        }
      }
    };
    
    export default connect(mapStateToProps, mapDispatchToProps)(About); 
    

    在redux中如何可以进行异步的操作?
    中间件(Middleware):

    • 目的是在dispatch的action和最终达到的reducer之间,扩展一些自己的代码。
    • 比如日志记录、调用异步接口、添加代码调试功能等等
    • 第三方库:redux-thunk;
      redux-thunk是如何做到让我们可以发送异步的请求?
    • 默认情况下的dispatch(action),action需要是一个JavaScript的对象
    • redux-thunk可以让dispatch(action函数),action可以是一个函数
    • 该函数会被调用,并且会传给这个函数一个dispatch函数和getState函数:
      dispatch函数用于我们之后再次派发action;
      getState函数考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态;

    yarn add redux-thunk
    yarn add axios

    上述案例的缺陷在“图一缺陷.jpg”中体现出来,接下来按照优化后的:
    store/index.js

    import { createStore, applyMiddleware } from 'redux';
    import thunkMiddleware from 'redux-thunk';
    import reducer from './reducer.js';
    
    //应用一些中间件
    const storeEnhancer = applyMiddleware(thunkMiddleware);
    const store = createStore(reducer,storeEnhancer);
    
    export default store;
    

    pages/home.js获取数据 (真正项目会这么做)

    import React, { PureComponent } from 'react';
    import { connect } from 'react-redux';
    
    import axios from 'axios';
    
    import { incAction, addAction, getHomeMultidataAction } from '../store/actionCreators'
    
    class Home extends PureComponent {
      componentDidMount() {
        this.props.getHomeMultidata();
      }
    
      render() {
        return (
          <div>
            <h1>Home</h1>
            <h2>当前计数: {this.props.counter}</h2>
            <button onClick={e => this.props.increment()}>+1</button>
            <button onClick={e => this.props.addNumber(5)}>+5</button>
          </div>
        )
      }
    }
    
    const mapStateToProps = state => ({
      counter: state.counter
    })
    
    const mapDispatchToProps = dispatch => ({
      increment() {
        // 本质上传递的是对象
        dispatch(incAction());
      },
      addNumber(num) {
      // 本质上传递的是对象
        dispatch(addAction(num));
      },
      getHomeMultidata() {
       // 这次传递的是函数
       dispatch(getHomeMultidataAction);
      }
    })
    
    export default connect(mapStateToProps, mapDispatchToProps)(Home);
    

    store/actionCreators.js

    import axios from 'axios';
    
    import {  ADD_NUMBER, SUB_NUMBER,INCREMENT,DECREMENT,CHANGE_BANNERS,CHANGE_RECOMMEND } from './constants.js';
    
    // export function addAction(num) {
    //   return {
    //     type: "ADD_NUMBER",
    //     num
    //   }
    // }
    
    // export const addAction = (num) => {
    //   return {
    //     type: "ADD_NUMBER",
    //     num
    //   }
    // }
    
    export const addAction = num => ({
      type: ADD_NUMBER,
      num
    });
    
    export const subAction = num => ({
      type: SUB_NUMBER,
      num
    });
    
    export const incAction = () => ({
      type: INCREMENT
    });
    
    export const decAction = () => ({
      type: DECREMENT
    });
    
    // 轮播图和推荐的action
    export const changeBannersAction = (banners) => ({
      type: CHANGE_BANNERS,
      banners
    });
    
    export const changeRecommendAction = (recommends) => ({
      type: CHANGE_RECOMMEND,
      recommends
    });
    
    // redux-thunk中定义的action函数
    export const getHomeMultidataAction = (dispatch, getState) => {
      axios({
        url: "http://123.207.32.32:8000/home/multidata",
      }).then(res => {
        const data = res.data.data;
        dispatch(changeBannersAction(data.banner.list));
        dispatch(changeRecommendAction(data.recommend.list));
      })
    }
    

    优化完成!

    相关文章

      网友评论

          本文标题:react_16Hooks_二(组件中的异步操作)

          本文链接:https://www.haomeiwen.com/subject/heyttdtx.html