Redux中间件了解

90 阅读4分钟

redux的中间件 官网

在了解中间件之前需要对redux等有基础了解

概念

Redux middleware 被用于解决不同的问题,它提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。 你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。

使用

以 redux-logger 为例:

1.安装

npm install redux-logger redux-promise redux-thunk redux-saga -S

引用

store/index.js

import { legacy_createStore as createStore, applyMiddleware } from "redux";
import reducer from './reducers'
import reduxLogger from 'redux-logger'
import reduxThunk from 'redux-thunk'
 
const store = createStore(
    reducer,
    applyMiddleware(reduxLogger, reduxThunk)
)
 
export default store 

2.使用步骤

  1. 从redux内解构出applyMiddleware
  2. 导入需要使用的中间件 例如:redux-logger
  3. 中间件传入 applyMiddleware 作为createStore()的第二个参数

上面这一部分,等于 redux-logger 中间件添加完成✅

整体项目例子

store内的全量代码 Redux工程化开发

页面内容代码:React-redux 插件 了解及使用

但是中间件内部用法一致可以不看例子,具体内部的截图内容来源是这个例子代码

redux-logger

用于每一次派发,在控制台输出派发日志,方便对redux操作进行调试。 输出内容有:派发之前的状态、派发行为、派发后的状态。

添加 redux-logger 中间件后,派发了会进行数据记录。

图片.png

redux-thunk

在不使用中间件之前,redux执行都是同步的,如果需要进行处理等操作,就需要用到中间件, 这里的 redux-thunk/ redux-promise 均可进行异步派发

redux-thunk 用于实现异步派发,(每一次派发的时候,需要传递给reducer的action对象中的内容,是需要异步获取的)

当内部不使用dispatch的情况时:内部为同步操作,直接修改数据,没有可以添加的内容

// 初始代码
add() {
    return {
        type: TYPES.COUNT_INCREASE
    }
}

添加 redux-thunk 代码实现:

const countAction = {
    add() {
        return async (dispatch, getState) => {
            // 代码内部操作
        }
    }
}



const countAction = {
    add() {
        return async (dispatch, getState) => {
        // dispatch 是用来派发 action
        // getState 用于获取数据
            await delay()   // delay 模拟异步操作
            dispatch({
                type: TYPES.COUNT_INCREASE
            })
        }
    }
}

运行结果:

图片.png

可以看到,在异步操作完成后,我们基于基于真正的dispatch实现派发,通知reducer执行,实现状态更改!

原理

根据上方的运行截图可以看到: 在点击增加后,dispatch派发了两次

1.第一次执行返回一个函数,内部给函数设置了一个type属性,属性值不会和reducer内的逻辑匹配

第一次派发 dispatch函数,type和reducer内的逻辑不匹配,所以无任何状态改变

2.把返回的函数执行,把派发的dispatch传递给函数

在dispatch内进行派发 store内获取到的是传递过去的函数

redux-promise

也是实现异步派发操作的中间件,写法和redux-thunk有差异

引入方法同上方操作

const countAction = {
    async sub() {
        await delay(3000)
        return {
            type: TYPES.COUNT_DECREASE
        }
    }
}

点击减少运行:

图片.png

原理

第一次点击反对按钮:

dispatch(voteAction.oppose())

  1. 此dispatch也是被重写的,传递进来的是promise 实例:
  • 没有type 屬性,但是不报错

  • 也不会通知reducer执行

  1. 但是他会 监听 voteAction.oppose 执行的返回值 「promise 实例」

等待实例为成功的时候,它内部会自动再派发一次任务:

  • 用到的是store.dispatch派发「会通知reducer执行了」

  • 把实例为成功会的结果「也就是我们返回的标准的action对象』传递给reducer,实现状态更改!!

二者区别(redux-thunk 和redux-promise)

reduxpromise和redux thunk中间件,都是处理异步派发的,他们相同的地方

  1. 都是派发两次
  • 第一次派发用的是,重写后的dispatch:这个方法不会去校验对象是否有 type属性;也不会在乎传递的对象是否为标准普通对象!!

  • 此次派发,仅仅是为了第二次派发做准备

  • redux-thunk:把返回的函数执行,把真正的dispath传递给函数

  • redux-promise:监听返回的promise实例,在实例为成功后,需要基于真正的disptch,把成功的结果,再进行派发!!!

区别: redux-thunk 第二次派发是手动处理 redux-promise 是自动处理

代码

countAction.js 的全量代码 可以和它对比下 Redux工程化开发

路径:store/action/countAction.js

import * as TYPES from '../action-types'

const delay = (interval = 1000) => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve()
        }, interval)
    })
}

const countAction = {
    // 初始写法
    // add() {
    //     return {
    //         type: TYPES.COUNT_INCREASE
    //     }
    // }

    // redux-thunk 写法
    add() {
        return async (dispatch, getState) => {
            await delay()
            dispatch({
                type: TYPES.COUNT_INCREASE
            })
        }
    },
    // redux-promise 写法
    async sub() {
        await delay(3000)
        return {
            type: TYPES.COUNT_DECREASE
        }
    }
}

export default countAction