React系列:react-redux的理解和使用

635 阅读4分钟

目标

  1. 为什么要使用react-redux?
  2. react-redux为开发提供了什么?

回顾redux的基本使用

在使用redux之前,需要了解的是**redux不是react专属的**,所以在vueangular,甚至jQuery中都可以使用。

使用原生JavaScript来使用redux,在node环境下。

// 安装
npm install redux

开始使用redux

// index.js

// 导入redux,不用多说
const redux  = require('redux')

// 第一步: 初始化一个变量
const initState = {
    count: 0
}

// 第二步: 创建一个store对象,利用redux提供的createStore,参数为一个reducer函数
const store = redux.createStore(reducer)

// 第三步:由于上面需要一个reducer函数,所以创建一个reducer函数
function reducer(state = initState, action) {
    switch(action.type) {   //根据类型,判断执行哪个action
        case 'ADD': {   //加
            return {...state, count: state.count + 1}
        }
        case 'SUB': {   //减
            return {...state, count: state.count - action.num}
        }
       default: {  //返回默认值
            return state
        }
    }
}

由于处于node环境,上面的第三步第二步需要对调一下位置,理解意思就行了。

上面创建一个store对象就已经存在了,那么就可以开始使用store对象

// 第四步:调用store对象提供的subscribe方法,来监听store的变化,只要发生变化,就会触发
store.subscribe(() => {
    console.log(store.getState());
})

// 第五步:触发动作(使用store对象提供的dispatch来触发reducer函数)
const action = {
    type: 'SUB',
    num: 12
}
store.dispatch(action)
// 根据type去匹配reducer函数中的type值,从而修改state

上面大致就是redux的基本执行流程:

  1. 定义一个初始值
  2. 创建一个store对象
  3. 定义一个reducer函数,在创建store对象的时候使用。
  4. 调用store.subscribe 来监听state的变化。
  5. 触发动作(改变state的值),store.dispatch()执行动作。

react中使用redux

虽然redux可以在其他的地方使用,但是最普遍的还是在react中使用,实现数据的状态管理。

如果在react组件中,使用redux的话,肯定会有三个步骤:

  1. 导入state数据到组件。
  2. 在组件加载的时候,监听state数据的变化。
  3. 在组件卸载的时候,取消监听state数据变化。
// 那么就会出现,每个组件中,大致有这样的几行代码

// 导入整体的state
import stores from 'src/stores'

// 在组件加载的时候,监听state数据变化
componentDidMount() {
    this.unSubScribe = store.subscribe(() => {
        this.setState({
            counter: stores.getState.count
        })
    })
}    

// 组件卸载的时候,取消监听
componentWillUnmount() {
    this.unSubScribe()
}

store.subscribe()的返回值,是一个取消监听的函数,执行该函数,就取消监听。

这样就会想,如果每个组件都有这样的几行代码,那么根据开发思想,就会进行代码抽离

代码抽离

抽离的实现: 利用高阶组件(HOC)

import React, {PureComponent} from 'react

// 导入store
import stores from '../stores'

export default function connect(mapStateToProps, mapDispatchToProps) {
  return function HandleNewCom(WrapComponent) {
    return class extends PureComponent {    //这里是使用的class表达式,可以不用写类名
      constructor(props) {
        super(props)
        this.state = {
          storeState: mapStateToProps(stores.getState())
        }
      }
          
      //在生命周期中处理订阅和取消订阅
      componentDidMount() {
        this.unSubScribe = store.subscribe(() => {
          this.setState({
            storeState: mapStateToProps(stores.getState())
          })
        })
      }   
      componentWillUnmount() {
        this.unSubScribe()
      }
          
      //这里我们把传递过来组件,重新return出去,也把store中的state值和store.dispatch传送过去
      return<WrapComponent  
        {...this.props }
        {...this.mapStateToProps(store.getState())}
        {...this.mapDispatchToProps(store.dispatch) }
      />
    }
  }
}

简单分析:

  • 执行connect 函数,返回一个组件,调用connect函数,就需要你手动的传递两个参数,并且这两个参数也是函数

    • mapStateToProps: 映射state到props中去。
    • mapDispatchToProps: 映射dispatch到props中。
  • connect函数,返回一个函数组件,函数组件接受一个参数,该参数也是组件

    • 这一步的目的就是为了注入state和dispatch到props
    • ...this.mapStateToProps(store.getState()): 注入mapStateToProps的返回值到props中
    • ...this.mapDispatchToProps(store.dispatch): 注入mapDispatchToProps的返回值到props中

具体使用:

// 定义两个函数,作为connect的参数
const mapStateToProps = (state) => {  // state:store.getState()调用传入的
  return {
    counter: state.counter
  }
};

const mapDispatchToProps = (dispatch) => { // dispatch: store.dispatch 调用传入的
  return {
    increment: (...args) => dispatch(actions.increment(...args)),
  }
};

// 调用connect函数,返回一个函数组件
const Com = connect(mapStateToProps, mapDispatchToProps)
// 函数组件,接受一个参数:组件,返回一个组件(HOC)
const NewCount = Com(Count)
export default NewCount;

// 连起来写
export default connect(mapStateToProps, mapDispatchToProps)(Count)

这样,redux在组件中,就不用每个组件都去写一边redux的监听事件等等,只需要调用connect函数即可,返回一个新的组件,新的组件就具有state的一些列操作。

react-redux的出现

在上面的connect函数实现中,其实还是比较的难理解,有点绕弯,高阶组件的应用什么的。(反正,我是理解很多遍的,太菜了)。

那么对于开发者而言,我们只想要connect函数,不想去实现它。所以,这下react-redux就出现了,react-redux里面,就提供了connect函数,直接使用即可。

import { connect } from 'react-redux';

是不是 very happy。

并在react-redux中还提供了Provider的组件(利用useContext实现的),在项目的入口文件处,主组件中提供,在所有的子组件中都能使用。

import {Provider} from "react-redux";

 <Provider store={store}>
    <App/>
 </Provider>

从react16.8以后,hooks的出现,react-redux有提供了两个hooks,用来拿取state和dispatch

import { useSelector, useDispatch } from 'react-redux';

并且useSelector 还可以做性能优化,利用第二个参数的浅层比较。

总结

  1. 为什么要使用react-redux?

    封装了一些使用redux的通用逻辑,可以直接调用API

  2. react-redux为开发提供了什么?

    针对类组件 :connect函数Provider组件

    针对函数组件: useSelector, useDispatch 两个hooks,Provider组件