• React 全栈体系(十三)


    第七章 redux

    五、redux 异步编程

    1. 理解

    • redux 默认是不能进行异步处理的,
    • 某些时候应用中需要在 redux 中执行异步任务(ajax, 定时器)

    2. 使用异步中间件

    • npm install --save redux-thunk

    3. 代码 - 异步 action 版

    3.1 store
    /* src/redux/store.js */
    /**
     * 该文件专门用于暴露一个store对象,整个应用只有一个store对象
     */
    //引入createStore,专门用于创建redux中最为核心的store对象
    import { createStore, applyMiddleware } from "redux";
    //引入为Count组件服务的reducer
    import countReducer from "./count_reducer";
    //引入redux-thunk,用于支持异步action
    import thunk from 'redux-thunk'
    //暴露store
    export default createStore(countReducer, applyMiddleware(thunk));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    3.2 count_action
    /* src/redux/count_action.js */
    /**
     * 该文件专门为Count组件生成action对象
     */
    import { INCREMENT, DECREMENT } from "./constant";
    
    //同步action,就是指action的值为Object类型的一般对象
    export const createIncrementAction = (data) => ({ type: INCREMENT, data });
    export const createDecrementAction = (data) => ({ type: DECREMENT, data });
    
    //异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的
    export const createIncrementAsyncAction = (data, time) => {
      return (dispatch) => {
        setTimeout(() => {
          dispatch(createIncrementAction(data));
        }, time);
      };
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    3.3 Count
    /* src/components/Count/index.jsx */
    import React, { Component } from "react";
    //引入store,用于获取redux中保存状态
    import store from "../../redux/store";
    //引入actionCreator,专门用于创建action对象
    import {
      createDecrementAction,
      createIncrementAction,
      createIncrementAsyncAction,
    } from "../../redux/count_action";
    
    export default class Count extends Component {
      //加法
      increment = () => {
        const { value } = this.selectNumber;
        store.dispatch(createIncrementAction(value * 1));
      };
      //减法
      decrement = () => {
        const { value } = this.selectNumber;
        store.dispatch(createDecrementAction(value * 1));
      };
      //奇数加
      incrementIfOdd = () => {
        const { value } = this.selectNumber;
        const count = store.getState();
        if (count % 2 !== 0) {
          store.dispatch(createIncrementAction(value * 1));
        }
      };
      //异步加
      incrementAsync = () => {
        const { value } = this.selectNumber;
        store.dispatch(createIncrementAsyncAction(value * 1, 500));
      };
      render() {
        return (
          <div>
            <h1>当前求和为:{store.getState()}</h1>
            <select ref={(c) => (this.selectNumber = c)}>
              <option value="1">1</option>
              <option value="2">2</option>
              <option value="3">3</option>
            </select>
            &nbsp;
            <button onClick={this.increment}>+</button>&nbsp;
            <button onClick={this.decrement}>-</button>&nbsp;
            <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
            <button onClick={this.incrementAsync}>异步加</button>
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    3.4 总结
    (1).明确:延迟的动作不想交给组件自身,想交给action
    (2).何时需要异步action:想要对状态进行操作,但是具体的数据靠异步任务返回。
    (3).具体编码:
    	1).yarn add redux-thunk,并配置在store中
    	2).创建action的函数不再返回一般对象,而是一个函数,该函数中写异步任务。
    	3).异步任务有结果后,分发一个同步的action去真正操作数据。
    (4).备注:异步action不是必须要写的,完全可以自己等待异步任务的结果了再去分发同步action。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    六、react-redux

    在这里插入图片描述

    1. 理解

    • 一个 react 插件库
    • 专门用来简化 react 应用中使用 redux

    2. react-Redux 将所有组件分成两大类

    2.1 UI 组件
    • 只负责 UI 的呈现,不带有任何业务逻辑
    • 通过 props 接收数据(一般数据和函数)
    • 不使用任何 Redux 的 API
    • 一般保存在 components 文件夹下
    2.2 容器组件
    • 负责管理数据和业务逻辑,不负责 UI 的呈现
    • 使用 Redux 的 API
    • 一般保存在 containers 文件夹下
    2.3 相关 API
    2.3.1 Provider:让所有组件都可以得到 state 数据
    <Provider store={store}>
      <App />
    </Provider>
    
    • 1
    • 2
    • 3
    2.3.2 connect:用于包装 UI 组件生成容器组件
    import { connect } from 'react-redux'
      connect(
        mapStateToprops,
        mapDispatchToProps
      )(Counter)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    2.3.3 mapStateToprops:将外部的数据(即 state 对象)转换为 UI 组件的标签属性
    const mapStateToprops = function (state) {
      return {
        value: state
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    2.3.4 mapDispatchToProps:将分发 action 的函数转换为 UI 组件的标签属性

    3. 代码 - react-redux 的基本使用

    • 安装:npm install react-redux
    3.1 index
    /* src/index.js */
    //引入react核心库
    import React from "react";
    //引入ReactDOM
    import ReactDOM from "react-dom";
    //引入App组件
    import App from "./App";
    import store from "./redux/store";
    
    ReactDOM.render(<App />, document.getElementById("root"));
    //监测redux中状态的改变,如redux的状态发生了改变,那么重新渲染App组件
    store.subscribe(() => {
      ReactDOM.render(<App />, document.getElementById("root"));
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    3.2 App
    /* src/App.jsx */
    import React, { Component } from "react";
    import Count from "./containers/Count";
    import store from "./redux/store";
    
    export default class App extends Component {
      render() {
        return (
          <div>
            {/* 给容器组件传递store */}
            <Count store={store} />
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    3.3 Count(Component)
    /* src/components/Count/index.jsx */
    import React, { Component } from "react";
    
    export default class Count extends Component {
      //加法
      increment = () => {
        const { value } = this.selectNumber;
        this.props.jia(value * 1);
      };
      //减法
      decrement = () => {
        const { value } = this.selectNumber;
        this.props.jian(value * 1);
      };
      //奇数加
      incrementIfOdd = () => {
        const { value } = this.selectNumber;
        if (this.props.count % 2 !== 0) {
          this.props.jia(value * 1);
        }
      };
      //异步加
      incrementAsync = () => {
        const { value } = this.selectNumber;
        this.props.jiaAsync(value * 1, 500);
      };
      render() {
        return (
          <div>
            <h1>当前求和为:{this.props.count}</h1>
            <select ref={(c) => (this.selectNumber = c)}>
              <option value="1">1</option>
              <option value="2">2</option>
              <option value="3">3</option>
            </select>
            &nbsp;
            <button onClick={this.increment}>+</button>&nbsp;
            <button onClick={this.decrement}>-</button>&nbsp;
            <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
            <button onClick={this.incrementAsync}>异步加</button>
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    3.4 Count(Container)
    /* src/containers/Count/index.jsx */
    //引入Count的UI组件
    import CountUI from "../../components/Count";
    import {
      createIncrementAction,
      createDecrementAction,
      createIncrementAsyncAction,
    } from "../../redux/count_action";
    
    //引入connect用于连接UI组件与redux
    import { connect } from "react-redux";
    
    /*
    	1.mapStateToProps函数返回的是一个对象;
    	2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
    	3.mapStateToProps用于传递状态
    */
    function mapStateToProps(state) {
      return { count: state };
    }
    
    /*
    	1.mapDispatchToProps函数返回的是一个对象;
    	2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
    	3.mapDispatchToProps用于传递操作状态的方法
    */
    function mapDispatchToProps(dispatch) {
      return {
        jia: (number) => dispatch(createIncrementAction(number)),
        jian: (number) => dispatch(createDecrementAction(number)),
        jiaAsync: (number, time) =>
          dispatch(createIncrementAsyncAction(number, time)),
      };
    }
    //使用connect()()创建并暴露一个Count的容器组件
    export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    3.5 总结
    (1).明确两个概念:
    	1).UI组件:不能使用任何redux的api,只负责页面的呈现、交互等。
    	2).容器组件:负责和redux通信,将结果交给UI组件。
    (2).如何创建一个容器组件————靠 react-redux 的 connect函数
    	connect(mapStateToProps,mapDispatchToProps)(UI组件)
    		-mapStateToProps:映射状态,返回值是一个对象
    		-mapDispatchToProps:映射操作状态的方法,返回值是一个对象
    (3).备注1:容器组件中的store是靠props传进去的,而不是在容器组件中直接引入
    (4).备注2:mapDispatchToProps,也可以是一个对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4. 代码 - 优化 1:简写 mapDispatch

    Count(Container)
    /* src/containers/Count/index.jsx */
    //引入Count的UI组件
    import CountUI from "../../components/Count";
    import {
      createIncrementAction,
      createDecrementAction,
      createIncrementAsyncAction,
    } from "../../redux/count_action";
    
    //引入connect用于连接UI组件与redux
    import { connect } from "react-redux";
    
    //使用connect()()创建并暴露一个Count的容器组件
    export default connect((state) => ({ count: state }), {
      jia: createIncrementAction,
      jian: createDecrementAction,
      jiaAsync: createIncrementAsyncAction,
    })(CountUI);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    5. 代码 - 优化 2:Provider 组件的使用

    5.1 index
    /* src/index.js */
    //引入react核心库
    import React from "react";
    //引入ReactDOM
    import ReactDOM from "react-dom";
    //引入App组件
    import App from "./App";
    import store from "./redux/store";
    import { Provider } from "react-redux";
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById("root")
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    5.2 App
    /* src/App.jsx */
    import React, { Component } from "react";
    import Count from "./containers/Count";
    
    export default class App extends Component {
      render() {
        return (
          <div>
            <Count />
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    6. 代码 - 优化 3:整合 UI 组件和容器组件

    6.1 Count(Container)
    /* src/containers/Count/index.jsx */
    import React, { Component } from "react";
    import {
      createIncrementAction,
      createDecrementAction,
      createIncrementAsyncAction,
    } from "../../redux/count_action";
    
    //引入connect用于连接UI组件与redux
    import { connect } from "react-redux";
    
    // 定义UI组件
    class Count extends Component {
      //加法
      increment = () => {
        const { value } = this.selectNumber;
        this.props.jia(value * 1);
      };
      //减法
      decrement = () => {
        const { value } = this.selectNumber;
        this.props.jian(value * 1);
      };
      //奇数加
      incrementIfOdd = () => {
        const { value } = this.selectNumber;
        if (this.props.count % 2 !== 0) {
          this.props.jia(value * 1);
        }
      };
      //异步加
      incrementAsync = () => {
        const { value } = this.selectNumber;
        this.props.jiaAsync(value * 1, 500);
      };
      render() {
        return (
          <div>
            <h1>当前求和为:{this.props.count}</h1>
            <select ref={(c) => (this.selectNumber = c)}>
              <option value="1">1</option>
              <option value="2">2</option>
              <option value="3">3</option>
            </select>
            &nbsp;
            <button onClick={this.increment}>+</button>&nbsp;
            <button onClick={this.decrement}>-</button>&nbsp;
            <button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
            <button onClick={this.incrementAsync}>异步加</button>
          </div>
        );
      }
    }
    
    
    //使用connect()()创建并暴露一个Count的容器组件
    export default connect((state) => ({ count: state }), {
      jia: createIncrementAction,
      jian: createDecrementAction,
      jiaAsync: createIncrementAsyncAction,
    })(Count);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    6.2 总结
    (1).容器组件和UI组件整合一个文件
    (2).无需自己给容器组件传递store,给<App/>包裹一个<Provider store={store}>即可。
    (3).使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。
    (4).mapDispatchToProps也可以简单的写成一个对象
    (5).一个组件要和redux“打交道”要经过哪几步?
    	(1).定义好UI组件---不暴露
    	(2).引入connect生成一个容器组件,并暴露,写法如下:
    			connect(
    				state => ({key:value}), //映射状态
    				{key:xxxxxAction} //映射操作状态的方法
    			)(UI组件)
    	(3).在UI组件中通过this.props.xxxxxxx读取和操作状态
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    k8s 1.28版本二进制安装
    BadNets:基于数据投毒的模型后门攻击代码(Pytorch)以MNIST为例
    突破界限的力量:探索Facebook如何打破国界、文化和语言的障碍
    电大搜题——打开学习之门的最佳选择
    QianBase 运维实用命令
    逆向-还原代码之url_encode (Interl 32)
    智慧城管系列-0-项目实战-资料
    VUE3子表格嵌套分页查询互相干扰的问题解决
    Jmeter怎么实现接口关联?
    2022 年你必须准备的 115 个 SQL 面试问题
  • 原文地址:https://blog.csdn.net/sgsgkxkx/article/details/133179706