Redux快速上手之【redux中间件及处理机制】

前言

  • 细阅此文章大概需要 <math xmlns="http://www.w3.org/1998/Math/MathML"> 7 分钟 \color{red}{7分钟} </math>7分钟左右

  • 本篇中讲述了:

    1. 什么是中间件
    2. 常见的中间件
    3. 中间件的使用
    4. 异步派发为什么要使用中间件
    5. redux-thunk中间件的使用及原理
    6. redux-promise中间件的使用及原理
    7. redux-thunkredux-promise的异同
  • 欢迎在评论区探讨、留言,如果认为有任何错误都还请您不吝赐教,万分感谢。希望今后能和大家共同学习、进步。

  • 下一篇会尽快更新,已经写好的文章也会在今后进行不定期的修订、更新。

  • 如果觉得这篇文章对您有帮助,还请点个赞支持一下,谢谢大家!

  • 欢迎转载,注明出处即可。


什么是中间件

当我们在执行dispatch派发时,如果使用了中间件,那么派发前就会先经过中间件去执行一系列操作,然后再进行派发。


常见的中间件

redux-logger

此中间件提供了日志能力,当我们每次进行派发的时候,它可以在控制台输出日志。日志内容包括:派发前的状态派发的行为派发后的状态

redux-thunk/redux-promise

这两种中间件提供了异步派发的能力。每次派发的时候,需要传递给reduceraction对象中的内容是需要异步进行获取的。

redux-saga


中间件的使用

redux中使用中间件,需要配合applyMiddleware这个api来使用。applyMiddleware方法可以接收多个中间件实例/方法作为参数。

js 复制代码
// 创建公共容器
import {createStore, applyMiddleware} from 'redux'
import reducer from './reducer'
import reduxLogger from 'redux-logger' // 引入logger中间件

/*创建公共容器*/
const store = createStore(
    reducer,
    applyMiddleware(reduxLogger) //在创建公共容器时,通过applyMiddleware来注入并使用中间件,这里可以传入多个中间件
)

export defualt store

异步派发为什么要使用中间件

当不使用任何中间件的情况下,在actionCreator对象中,是不支持异步操作的。因为如果我们自己通过promise来实现异步派发,action得到的是一个promise实例,并不是一个标准的action对象,且不存在type属性。要保证方法的执行,必须立即返回标准的action对象

而在应用的redux的项目中,往往很多时候,都需要用到异步派发:比如我们派发后,需要先请求数据,等到数据回来,在进行派发操作。

这种场景下,官方最为推荐的就是使用redux-thunk中间件。

js 复制代码
// 创建公共容器
import {createStore, applyMiddleware} from 'redux'
import reducer from './reducer'
import reduxLogger from 'redux-logger'
import reduxThunk from 'redux-thunk' // 引入thunk中间件

/*创建公共容器*/
const store = createStore(
    reducer,
    applyMiddleware(reduxLogger, reduxThunk) //在创建公共容器时,通过applyMiddleware来注入并使用中间件,这里可以传入多个中间件
)

export defualt store

thunk中间件的使用及原理

使用

在使用上和logger差不多,都需要通过applyMiddleware来注入。 唯一不同的地方在于:actionCreator在编写时候的结构有所调整,要求我们先返回一个函数,然后在这个函数中进行异步操作,等到异步操作完成,在手动进行dispatch派发

原理

  1. 当我们触发交互,执行adda方法,会将moduleAAction.adda()执行,执行的返回值进行派发

第一次派发:派发的其实是一个函数,这次派发用到的dispatch其实是重写的这个dispatch,传递给dispatch的其实是一个函数【无type】,此时不会报错,也不会通知reducer执行,仅仅是返回的这个函数执行了。

实际上可以看作是:

  1. 首先方法执行会返回一个函数,函数本身也是一个实例,所以在内部的处理中会给这个实例设置一个type属性,属性值不会和reducer中的逻辑进行匹配,所以不会造成任何状态的修改。
  2. 将返回的函数执行,把派发的方法dispatch传递给函数,在这个函数中,我们可以进行异步操作。当异步操作成功后,我们再手动基于传递进来的dispatch进行派发即可。

第二次派发:使用的dispatch其实是刚才我们手动传入函数的dispatch,这个dispatch才是store真正的dispatch方法。当在函数中异步成功后,我们在基于传递进来的这个真正的dispatch进行派发即可,此时会通知reducer执行,修改对应状态。

示例

js 复制代码
/* moduleAAction.js */
import * as TYPES from '../action-types'

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


const moduleAAction = {
    // redux-thunk中间件的语法,
    adda(){ 
        return async (dispatch)=>{
            await delay()
            dispatch({ type:TYPES.moduleA_ADDA })
        }
        // return {type:TYPES.moduleA_ADDA} 
    }
    addb(){ return {type:TYPES.moduleA_ADDB} }
}

export default moduleAAction

但是每次异步派发的时候,都需要这样手动写这样的结构,还是不够方便,有没有更简单一点的?那接下来,我们来看 redux-promise中间件


promise中间件的使用及原理

使用

我们无需再手动修改actionCreator在编写时候的结构,只需要在actionCreator中,直接使用异步操作就可以,在异步操作后直接返回action对象即可。 使用上比thunk简单了不止一点半点。

redux-thunk的区别

其实两种中间件处理异步操作的原理都是一致的,都要派发两次,第一次派发的dispatch也是被重写的,区别在于它监听的是返回的promise实例,在实例成功后,基于真正的dispatch,把成功的结果再进行派发。而且第二次派发是其内部自动处理的。

原理

  1. 当我们触发交互,执行addb方法,dispatch会将moduleAAction.addb()执行

第一次派发的dispatch也是被重写的,是传递进来的promise实例,也没有type属性但不会报错,也不会通知reducer执行。

实际上可以看作是:

  1. 其内部会监听moduleAAction.addb()执行的返回值:【一个promise实例】等实例的状态变为成功时,其内部会再进行一次派发。这次派发用到的是store真正的dispatch方法,将会通知reducer执行。同时会将成功的结果【我们返回的action对象】传递给reducer,实现状态的修改

示例

js 复制代码
// 创建公共容器
import {createStore, applyMiddleware} from 'redux'
import reducer from './reducer'
import reduxLogger from 'redux-logger'
import reduxThunk from 'redux-thunk'
import reduxPromise from 'redux-promise' // 引入promise中间件

/*创建公共容器*/
const store = createStore(
    reducer,
    applyMiddleware(reduxLogger, reduxThunk, reduxPromise) //在创建公共容器时,通过applyMiddleware来注入并使用中间件,这里可以传入多个中间件
)

export defualt store
js 复制代码
/* moduleAAction.js */
import * as TYPES from '../action-types'

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


const moduleAAction = {
    // redux-thunk中间件的语法
    adda(){ 
        return async (dispatch)=>{
            await delay()
            dispatch({ type:TYPES.moduleA_ADDA })
        }
        // return {type:TYPES.moduleA_ADDA} 
    }
    // redux-promise中间件的语法
    addb(){ 
        await delay()
        return {type:TYPES.moduleA_ADDB}
        // return {type:TYPES.moduleA_ADDB}
    }
}

export default moduleAAction

redux-thunkredux-promise的异同

相同点

  1. 都是用来处理异步派发的
  2. 都是派发两次
  3. 第一次派发都是使用重写过后的dispatch

第一次派发使用重写过的dispatch为的是避免校验对象是否具有type属性,也不会在乎传递的到底是不是标准的action对象。

  1. 第一次派发都是为了第二次(真正的)派发做准备

不同点

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

redux-thunk的第二次派发是手动处理的

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

redux-promise的第二次派发是其内部自动处理的

相关推荐
love黄甜心几秒前
CSS3:深度解析与实战应用
前端·css·css3
安分小尧22 分钟前
从树形数据中找路径:解密 getLevelIdAll 的递归魔法
开发语言·前端·javascript
Apifox23 分钟前
Apifox 3月更新|发布/分享的API文档全面升级、支持MCP、支持调试Ollama本地部署AI大模型接口、新增「鉴权组件」
前端·后端·测试
华科云商xiao徐1 小时前
Python爬虫HTTP代理使用教程
前端
加个鸡腿儿1 小时前
vue+node+wabpack|动态环境配置加载技术文档
前端
90后的晨仔1 小时前
Flutter 基础知识(一)
前端
JasonYin1 小时前
血泪总结!Android传统项目接入Compose的7大深坑与填坑方案
前端
ssshooter1 小时前
怎么在任何项目使用 Tailwind CSS
前端·css·面试
kovlistudio1 小时前
红宝书第十八讲:详解JavaScript的async/await与错误处理
开发语言·前端·javascript·学习
rainoway1 小时前
全量加载、懒加载、延迟加载、虚拟列表、canvas、异步分片
前端·算法·性能优化