• 集中式状态管理<react-redux>基本使用与优化


    在这里插入图片描述

    欢迎来到我的博客
    📔博主是一名大学在读本科生,主要学习方向是前端。
    🍭目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
    🛠目前正在学习的是🔥 R e a c t 框架 React框架 React框架🔥,中间穿插了一些基础知识的回顾
    🌈博客主页👉codeMak1r.的博客

    本文被专栏【React–从基础到实战】收录

    🕹坚持创作✏️,一起学习📖,码出未来👨🏻‍💻!
    在这里插入图片描述

    1、react-redux

    在这里插入图片描述
    react-redux把组件分为两类,一类叫做UI组件,一类叫做容器组件;

    UI组件的外侧都要包裹一个容器组件。

    注意⚠️:本文使用的示例为之前的文章中的示例。在之前的文章中已经做过了介绍,在本文就不再阐述。

    建议阅读顺序是:
    【redux工作流程】
    【redux异步action】
    👉再到本文

    2、连接容器组件与UI组件

    UI组件存放在components文件夹中,我们可以在src目录下新建文件夹containers,专门用于存放容器组件

    例如:Count组件的容器组件:/src/containers/Count/index.jsx

    /*
      该组件是Count组件这个UI组件的容器组件
     */
    // 引入Count组件的UI组件
    import CountUI from '../../components/Count'
    // 引入connect用于连接UI组件与容器组件
    import { connect } from 'react-redux'
    
    //创建并暴露一个Count的容器组件,connect()()的含义是:调用connect()这个函数返回的函数
    export default connect()(CountUI)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    代码解释:

    引入CountUI,为Count组件的UI组件,从原理图中来看,该组件是Count容器组件的子组件。

    引入connect函数,用于连接UI组件与容器组件;

    我们从原理图中可以看出,redux要想工作,必须要连接UI组件与容器组件,还必须连接容器组件与store。

    那么我们在容器组件中,使用connect()()的方法连接了UI组件

    【connect()()的含义:调用connect()这个函数的返回值,返回值本身是一个函数,也就是调用返回的函数】

    现在还需要让容器组件与store建立起连接;

    怎么让容器组件与store建立起连接呢?

    我们之前在App组件中一直都是渲染Count的UI组件的,但是我们现在引入了Count的容器组件(为Count的UI组件的父组件),那么我们可以直接在App组件中直接渲染Count组件的容器组件:

    // 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

    重点⚠️在于,

    在渲染Count组件的容器组件时,通过组件的props属性,将store传入Count组件的容器组件,从而实现容器组件与store建立起连接。

    3、react-redux基本使用

    现在我们已经把UI组件与容器组件建立起连接了,并且将容器组件与store也建立起连接了,那么我们接下来一起来探索react-redux是怎么工作,如何使用的呢?

    从流程图可以看出,我们需要向UI组件传递state(状态)和dispatch(操作状态的方法)。

    但是我们在UI组件的父组件,也就是Count的容器组件中,并没有以组件标签()的形式去渲染子组件

    而是通过react-redux提供的connect方法将父子组件建立起的联系,我们就需要通过connect方法传递props。

    我们之前知道,我们在调用connect方法返回的函数时需要传递UI组件作为参数,以将容器组件与UI组件连接起来,也就是

    connect()(CountUI)
    
    • 1

    而传递props时,我们需要在调用connect方法时直接传入两个参数(也就是connect的第一个括号内的参数),并且这两个参数都是函数形式的参数。具体看代码吧~

    connect(mapStateToProps, mapDispatchToProps)(CountUI)
    
    • 1

    说明:第一个函数参数mapStateToProps作用是将存放在store中的状态映射给UI组件的props;

    第二个函数参数mapDispatchToProps作用是将操作数据的方法映射给UI组件的props;

    其实也就对应图中的

    在这里插入图片描述

    具体实现如下:

    /*
      该组件是Count组件这个UI组件的容器组件
     */
    import CountUI from '../../components/Count'
    import { connect } from 'react-redux'
    import {
      createIncrementAction,
      createDecrementAction,
      createIncrementAsyncAction
    } from '../../redux/count_action_creator'
    /* 
      1.mapStateToProps函数返回的是一个对象;
      2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
      3.mapStateToProps用于传递状态
    */
    function mapStateToProps(state) {
      return { count: state }
    }
    
    function mapDispatchToProps(dispatch) {
      return {
        jia: (data) => {
          // 通知redux执行加法
          dispatch(createIncrementAction(data))
        },
        jian: (data) => {
          dispatch(createDecrementAction(data))
        },
        jiaAsync: (data, time) => {
          dispatch(createIncrementAsyncAction(data, time))
        }
      }
    }
    
    //创建并暴露一个Count的容器组件,connect()()的含义是:调用connect()这个函数返回的函数
    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

    这样一来,Count的UI组件就会接收到传递进来的props,我们可以通过props去渲染状态和操作状态:

    /src/components/Count/index.jsx:

    渲染状态:

    <h1>当前求和为:{this.props.count}</h1>
    
    • 1

    操作状态:

    // 加法
    increment = () => {
      const { value } = this.selectedNumber
      this.props.jia(value * 1)
    }
    // 减法
    decrement = () => {
      const { value } = this.selectedNumber
      this.props.jian(value * 1)
    }
    // 和为奇数时,加
    incrementIfOdd = () => {
      const { value } = this.selectedNumber
      if (this.props.count % 2 !== 0) {
        this.props.jia(value * 1)
      }
    }
    // 异步加
    incrementAsync = () => {
      const { value } = this.selectedNumber
      this.props.jiaAsync(value * 1, 500)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    react-redux基本使用总结:

    1. 明确两个概念:UI组件与容器组件

      UI组件:不能使用任何redux的api,只负责页面的呈现、交互等等;

      容器组件:负责和redux通信,将结果交给UI组件

    2. 如何创建一个容器组件——靠react-redux 的 connect函数

      connect(mapStateToProps, mapDispatchToProps)(CountUI)
      
      • 1

      mapStateToProps——映射状态,返回值是一个对象;

      mapDispatchToProps——映射操作状态的方法,返回值是一个对象

    3. 备注:容器组件中的store是靠props传入的,而不是在容器组件中直接引入。

    优化1、简写mapState和mapDispatch两个映射方法

    原映射方法:

    function mapStateToProps(state) {
      return { count: state }
    }
    
    function mapDispatchToProps(dispatch) {
      return {
        jia: (data) => {
          // 通知redux执行加法
          dispatch(createIncrementAction(data))
        },
        jian: (data) => {
          dispatch(createDecrementAction(data))
        },
        jiaAsync: (data, time) => {
          dispatch(createIncrementAsyncAction(data, time))
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    简写成箭头函数:

    const mapStateToProps = state => ({ count: state })
    
    const mapDispatchToProps = dispatch => (
      {
        jia: (data) => {
          // 通知redux执行加法
          dispatch(createIncrementAction(data))
        },
        jian: (data) => {
          dispatch(createDecrementAction(data))
        },
        jiaAsync: (data, time) => {
          dispatch(createIncrementAsyncAction(data, time))
        }
      }
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    当然,这只是在编码的角度对函数进行简化,我们还可以在API的角度,实现mapDispatch更为简洁的写法。

    其实mapDispatchToProps还可以是一个对象,在一般写法中,mapDispatchToProps是一个函数,但是可以简写成一个对象。

    export default connect(
      state => ({ count: state }),
    
      // mapDispatchToProps的简写——是一个对象
      {
        jia: createIncrementAction,
        jian: createDecrementAction,
        jiaAsync: createIncrementAsyncAction
      }
    
      // mapDispatchToProps一般写法——是一个函数
      /* dispatch => (
        {
          jia: (data) => {
            // 通知redux执行加法
            dispatch(createIncrementAction(data))
          },
          jian: (data) => {
            dispatch(createDecrementAction(data))
          },
          jiaAsync: (data, time) => {
            dispatch(createIncrementAsyncAction(data, time))
          }
        }
      ) */
    )(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

    把mapDispatchToProps简写成一个对象的话,react-redux会自动分发,也就是底层自动调用dispatch方法,所以我们在书写代码时并不需要手动调用dispatch方法,在mapDispatchToProps简写成一个对象时可以省略dispatch,这就是属于API层面的优化。

    优化2、Provider组件的使用

    在前面的连接容器组件和store的讲解中,我们提出:要想连接容器组件和store,就需要在App.jsx中通过props将store传入容器组件中。也就是这样子的:

    // 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

    现在我们基于react-redux,可以对App组件进行优化:

    // App.jsx
    import React, { Component } from 'react'
    import { Provider } from 'react-redux'
    import Count from './containers/Count'
    import store from './redux/store'
    
    export default class App extends Component {
      render() {
        return (
          <div>
            {/* 给容器组件传递store */}
            <Provider store={store}>
              <Count />
            </Provider>
          </div>
        )
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这样一来,哪怕我们需要连接多个容器组件到store,都只需要在渲染组件标签的外围包裹一个< Provider>标签即可。

    优化3、整合UI组件与容器组件

    前面两个优化,我们分别从代码层面和API层面进行了优化。在这里,我们将在文件层面对UI组件和容器组件进行优化。

    我们前面在逐步学习实践react-redux时,将容器组件放在containers文件夹中。但是我们发现,如果需要使用redux的UI组件越来越多的话,需要的容器组件也越来越多,到最后可能项目中有20个组件需要使用redux中的状态,那么我们真的就另外创建20个容器组件吗?

    O f c o u r s e n o t ! Of course not! Ofcoursenot!

    其实我们可以将UI组件与容器组件整合在同一个文件内!

    /src/containers/Count/index.jsx:

    import React, { Component } from 'react'
    // 引入connect用于连接UI组件与容器组件
    import { connect } from 'react-redux'
    import {
      createIncrementAction,
      createDecrementAction,
      createIncrementAsyncAction
    } from '../../redux/count_action_creator'
    
    // 定义UI组件Count
    class Count extends Component {
      // 加法
      increment = () => {
        const { value } = this.selectedNumber
        this.props.jia(value * 1)
      }
      // 减法
      decrement = () => {
        const { value } = this.selectedNumber
        this.props.jian(value * 1)
      }
      // 和为奇数时,加
      incrementIfOdd = () => {
        const { value } = this.selectedNumber
        if (this.props.count % 2 !== 0) {
          this.props.jia(value * 1)
        }
      }
      // 异步加
      incrementAsync = () => {
        const { value } = this.selectedNumber
        this.props.jiaAsync(value * 1, 500)
      }
    
      render() {
        return (
          <div>
            <h1>当前求和为:{this.props.count}</h1>
            <select ref={currentNode => { this.selectedNumber = currentNode }}>
              <option value="1">1</option>
              <option value="2">2</option>
              <option value="3">3</option>
            </select>&nbsp;&nbsp;&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>
        )
      }
    }
    // 创建并暴露一个Count的容器组件,connect()()的含义是:调用connect()这个函数返回的函数
    export default connect(
      state => ({ count: state }),
      // mapDispatchToProps的简写——是一个对象
      {
        jia: createIncrementAction,
        jian: createDecrementAction,
        jiaAsync: createIncrementAsyncAction
      }
      // mapDispatchToProps一般写法——是一个函数
    )(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
    • 62

    如此一来,我们就可以删除/src/components/Count/index.jsx了~

    优化总结

    1. 容器组件和UI组件整合为同一个文件

    2. 无需自己给容器组件传递store,给包裹一个标签,在Provider内传递store即可;

    3. 使用了react-redux后也不用再自己监测redux中状态的改变了,容器组件可以自动完成这个工作;

    4. mapDispatchToProps也可以简单的写成一个对象;

    5. 一个组件要和redux“打交道”要经过哪几步?

      1. 定义好UI组件——不暴露;
      2. 引入connect生成一个容器组件,并暴露,写法如下:
       connect(
      	state => ({key:value}), //映射状态
      	{key:xxxxAction}  //映射操作状态的方法
       )(UI组件)
      
      • 1
      • 2
      • 3
      • 4
      1. 在UI组件中通过this.props读取和操作状态。
  • 相关阅读:
    19.9 Boost Asio 同步字典传输
    Desthiobiotin衍生物Desthiobiotin-PEG4-Amine/Alkyne/Azide/DBCO
    传奇开服教程——legend/blue引擎替换和登陆器生成教程
    【C进阶】之数据类型起别名( typedef )
    Spring Cloud 运维篇1——Jenkins CI/CD 持续集成部署
    stata17中java installation not found或java not recognozed的问题
    学习开发一个RISC-V上的操作系统(汪辰老师) — 一次RV32I加法指令的反汇编
    代码随想录算法训练营29期Day63|LeetCode 503,42
    Softek Barcode Reader 9.1.5
    JDK1.8新特性:函数式接口
  • 原文地址:https://blog.csdn.net/Svik_zy/article/details/125951641