前言
-
细阅此文章大概需要 <math xmlns="http://www.w3.org/1998/Math/MathML"> 7 分钟 \color{red}{7分钟} </math>7分钟左右
-
本篇中讲述了:
- 什么是中间件
- 常见的中间件
- 中间件的使用
- 异步派发为什么要使用中间件
redux-thunk
中间件的使用及原理redux-promise
中间件的使用及原理redux-thunk
与redux-promise
的异同
-
欢迎在评论区探讨、留言,如果认为有任何错误都还请您不吝赐教,万分感谢。希望今后能和大家共同学习、进步。
-
下一篇会尽快更新,已经写好的文章也会在今后进行不定期的修订、更新。
-
如果觉得这篇文章对您有帮助,还请点个赞支持一下,谢谢大家!
-
欢迎转载,注明出处即可。
什么是中间件
当我们在执行dispatch派发时,如果使用了中间件,那么派发前就会先经过中间件去执行一系列操作,然后再进行派发。
常见的中间件
redux-logger
此中间件提供了日志能力,当我们每次进行派发的时候,它可以在控制台输出日志。日志内容包括:派发前的状态
、派发的行为
、派发后的状态
redux-thunk/redux-promise
这两种中间件提供了异步派发的能力。每次派发的时候,需要传递给reducer
的action
对象中的内容是需要异步进行获取的。
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派发
原理
- 当我们触发交互,执行
adda
方法,会将moduleAAction.adda()
执行,执行的返回值进行派发
第一次派发:派发的其实是一个函数,这次派发用到的dispatch其实是重写的这个dispatch,传递给dispatch的其实是一个函数【无type】,此时不会报错,也不会通知reducer执行,仅仅是返回的这个函数执行了。
实际上可以看作是:
- 首先方法执行会返回一个函数,函数本身也是一个实例,所以在内部的处理中会给这个实例设置一个
type
属性,属性值不会和reducer
中的逻辑进行匹配,所以不会造成任何状态的修改。 - 将返回的函数执行,把派发的方法
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
,把成功的结果再进行派发。而且第二次派发是其内部自动处理的。
原理
- 当我们触发交互,执行
addb
方法,dispatch会将moduleAAction.addb()
执行
第一次派发的dispatch也是被重写的,是传递进来的promise实例,也没有
type
属性但不会报错,也不会通知reducer
执行。实际上可以看作是:
- 其内部会监听
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-thunk
与redux-promise
的异同
相同点
- 都是用来处理异步派发的
- 都是派发两次
- 第一次派发都是使用重写过后的
dispatch
第一次派发使用重写过的
dispatch
为的是避免校验对象是否具有type属性,也不会在乎传递的到底是不是标准的action对象。
- 第一次派发都是为了第二次(真正的)派发做准备
不同点
redux-thunk
:把返回的函数执行,把真正的dispatch
传递给函数
redux-thunk
的第二次派发是手动处理的
redux-promise
:监听返回的promise实例,在实例成功后,基于真正的dispatch,把成功的结果再进行派发
redux-promise
的第二次派发是其内部自动处理的