@H_
502_0@
@H_
502_0@
原文链接
middleware 的由来
@H_
502_0@在业务中需要打印每一个 action 信息来调试,又或者希望 dispatch 或 reducer 拥有异步请求的
功能。面对这些场景时,一个个
修改 dispatch 或 reducer
代码有些乏力,我们需要一个可组合的、自由增减的
插件机制,Redux 借鉴了 Koa 中 middleware 的思想,利用它我们可以在前端应用中便捷地实现如日志打印、异步请求等
功能。
@H_
502_0@
@H_
502_0@比如在
项目中,进行了如下
调用后,redux 就集成了 thunk
函数调用以及打印日志的
功能。
import thunk from 'redux-thunk'
import logger from '../middleware/logger'
const enhancer = applyMiddleware(thunk,logger),// 以 redux-thunk、logger 中间件为例介绍中间件的使用
const store = createStore(rootReducer,enhancer)
@H_
502_0@下面追本溯源,来分析下源码。
applyMiddleware 调用入口
export default function createStore(reducer,preloadedState,enhancer) {
// 通过下面代码可以发现,如果 createStore 传入 2 个参数,第二个参数相当于就是 enhancer
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
return enhancer(createStore)(reducer,preloadedState)
}
...
}
@H_
502_0@由上述
createStore 源码发现,applyMiddleware 会进行
applyMiddleware(thunk,logger)(createStore)(reducer,preloadedState)
的
调用。
@H_
502_0@
applyMiddleware 源码如下
export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,// 调用 redux 原生方法,获取状态
dispatch: (...args) => dispatch(...args) // 调用 redux 原生 dispatch 方法
}
// 串行 middleware
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,dispatch // 返回加工过的 dispatch
}
}
}
@H_
502_0@可以发现 applyMiddleware 的作用其实就是返回加工过的 dispatch,下面会着重分析 middlewares 是如何串行起来的以及 dispatch 是如何被加工的。
串行 middleware
const middlewareAPI = {
getState: store.getState,dispatch: (...args) => dispatch(...args)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
@H_
502_0@观察上述
代码后发现每个 middleware 都会传入参数 middlewareAPI,来看下中间件
logger 的源码 以及
redux-thunk 的源码,发现中间件接受的第一个参数正是 ({ dispatch,getState })
// logger 源码
export default ({ dispatch,getState }) => next => action => {
console.log(action)
return next(action) // 经 compose 源码分析,此处 next 为 Store.dispatch
}
// redux-thunk 源码
export default ({ dispatch,getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch)
}
return next(action) // 此处 next 为 logger 中间件返回的 (action) => {} 函数
}
dispatch 是如何被加工的
@H_
502_0@接着上个小节,在
dispatch = compose(...chain)(store.dispatch)
中发现了 compose
函数,来看下
compose 的源码
export default function compose(...funcs) {
// ...
return funcs.reduce((a,b) => (...args) => a(b(...args)))
}
@H_
502_0@compose 源码中的
funcs.reduce((a,b) => (...args) => a(b(...args)))
算是比较重要的一句,它的作用是返回组合参数后的
函数,比如 compose(f,g,h) 等价于 (...args) => f(g(h(...args))),
效果图如下所示,
调用 this.props.dispatch() 后,会
调用相应的中间件,最终会
调用 redux 原生的 store.dispatch(),并且可以看到中间件
调用的形式类似数据结构中的栈(先进后出)。
@H_
502_0@
@H_
502_0@拿上个小节提到的 logger、redux-thunk 中间件为例,其 middleware 的内部串行
调用方式如下,从而完成了 dispatch
功能的增强(
支持如
this.props.dispatch(func)
的
调用以及日志
功能)。具体可以看
项目中的运用
action => {
if (typeof action === 'function') {
return action(dispatch)
}
return (action => {
console.log(action)
return store.dispatch(action)
})(action)
}
参考文献
@H_
502_0@深入React技术栈
原文链接:https://www.f2er.com/react/301882.html