redux
里,middleware
是发送action
和action
到达reducer
之间的第三方扩展,也就是中间层。也可以这样说,middleware
是架在action
和store
之间的一座桥梁redux
里,action
仅仅是携带了数据的普通js
对象
Reducer
拆分可以使组件获取其最小属性(state
),而不需要整个Store
。中间件则可以在Action Creator
返回最终可供dispatch
调用的action
之前处理各种事情,如异步API
调用、日志记录等,是扩展Redux
功能的一种推荐方式
Redux
提供了 applyMiddleware(...middlewares)
来将中间件应用到 createStore
。applyMiddleware
会返回一个函数,该函数接收原来的 creatStore
作为参数,返回一个应用了 middlewares
的增强后的 creatStore
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
//接收createStore参数
var store = createStore(reducer, preloadedState, enhancer)
var dispatch = store.dispatch
var chain = []
//传递给中间件的参数
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
//注册中间件调用链
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
//返回经middlewares增强后的createStore
return {
...store,
dispatch
}
}
}
未应用中间价之前,创建
store
的方式如下
import {createStore} from 'redux';
import reducers from './reducers/index';
export let store = createStore(reducers);
应用中间价之后,创建
store
的方式如下
import {createStore,applyMiddleware} from 'redux';
import reducers from './reducers/index';
let createStoreWithMiddleware = applyMiddleware(...middleware)(createStore);
export let store = createStoreWithMiddleware(reducers);
action creator
返回的值是这个action
类型的对象。然后通过store.dispatch()
进行分发action ---> dispatcher ---> reducers
如果遇到异步情况,比如点击一个按钮,希望2秒之后更新视图,显示消息“Hi”。我们可能这么写
ActionCreator
var asyncSayActionCreator = function (message) {
setTimeout(function () {
return {
type: 'SAY',
message
}
}, 2000)
}
这会报错,因为这个
asyncSayActionCreator
返回的不是一个action
,而是一个function
。这个返回值无法被reducer
识别
action
返回的是一个对象,而不是一个函数。如果返回函数,会出现错误action
的返回值是一个函数。那么咋办呢,所以需要引入中间件middleware
,它在中间起到了桥梁的作用,让action
的返回值可以是一个函数,从而传到reducer
那里。也就是说,中间件是用在action
发起之后,reducer
接收到之前的这个时间段Middleware
主要是负责改变Store
中的dispatch
方法,从而能处理不同类型的 action
输入,得到最终的 Javascript Plain Object
形式的 action
对象因此,上面那个
ActionCreator
就可以改写为这样:因为action
的返回值是一个函数
var asyncSayActionCreator = function (message) {
return function (dispatch) {
setTimeout(function () {
dispatch({
type: 'SAY',
message
})
}, 2000)
}
}
redux
中一个简单的同步数据流动的场景,点击button
后,在回调中 dispatch
一个 action
,reducer
收到action
后,更新 state
并通知 view
重新渲染middleware
后 redux
处理事件的逻辑,每一个 middleware
处理一个相对独立的业务需求,通过串联不同的 middleware
,实现变化多样的的功能。那么问题来了:middleware
怎么写?redux
是如何让 middlewares
串联并跑起来的?
Middleware
的中间件有很多,不过我的这个案例只引用了其中的一个,那就是redux-thunk
redux-thunk
源码如下export default function thunkMiddleware({ dispatch, getState }) {
return next => action =>
typeof action === 'function' ?
action(dispatch, getState) :
next(action);
}
意思是如果
action
是一个函数,执行这个action
函数,如果不是函数,执行next
函数
中间件的签名如下
({ getState, dispatch }) => next => action
根据
applyMiddleware
源码,每个中间件接收getState & dispatch
作为参数,并返回一个函数,该函数会被传入下一个中间件的 dispatch 方法,并返回一个接收action
的新函数
next(action)
的调用,都会导致action
执行失败function callTraceMiddleware ({dispatch,getState}){
return next=> action =>{
console.trace();
return next(action);
}
}
const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware,
loggerMiddleware,
callTraceMiddleware
)(createStore);
redux
的middleware
是对action
进行扩展处理,这样丰富了应用需求