「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」
Redux可以说是一个典型的小而精的lib,源码量及api数量都不多,但设计却十分巧妙。本系列将深入Redux5源码,探究其实现与设计。
applyMiddleware
Redux中的核心apicreateStore可以支持三个参数:createStore(reducer, [preloadedState], [enhancer]),第三个参数是store增强器,而Redux自带的唯一个enhancer便是applyMiddleware,因此在解析createStore之前,先来看一看applyMiddleware
源码实现
function applyMiddleware(
...middlewares
) {
return (createStore) =>(
reducer,
preloadedState
) => {
const store = createStore(reducer, preloadedState)
let dispatch = () => {
throw new Error(...)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (action, ...args) => dispatch(action, ...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
从源码可以看出,applyMiddleware的参数,即每一个中间件都是一个函数,并且这些函数都被compose组合了起来。这些中间件函数的类型定于如下
export interface Middleware<
_DispatchExt = {},
S = any,
D extends Dispatch = Dispatch
> {
(api: MiddlewareAPI<D, S>): (
next: D
) => (action: D extends Dispatch<infer A> ? A : never) => any
}
这些中间件函数,接收的参数是getState(虽然也有dispatch,但其实不可用),返回的也是一个函数:(next)=>(action)=>any,先称它为fn吧。chain数组中的每个成员都是这样的一个fn。
fn函数能通过闭包获取到getState,因此可以记录state的快照。而next参数其实是一个dispatch(初始是store.dispatch,之后是前一个fn返回的(action)=>any。这样就巧妙的实现了一个洋葱圈)这些fn函数又被compose组合为一个新的dispatch,从applyMiddleware中返回出来,成为store增加的dispatch。
因此当store调用dispatch的时候,fn可以通过action拿到dispatch的参数,通过getState获取前后的state,实现自己的中间件逻辑。
举个例子
以官网的log插件为例,可以更好地理解源码的运行过程。
import { createStore, applyMiddleware } from 'redux'
import todos from './reducers'
function logger({ getState }) {
return next => action => {
console.log('will dispatch', action)
const returnValue = next(action)
console.log('state after dispatch', getState())
return returnValue
}
}
const store = createStore(todos, ['Use Redux'], applyMiddleware(logger))
store.dispatch({
type: 'ADD_TODO',
text: 'Understand the middleware'
})
// will dispatch: { type: 'ADD_TODO', text: 'Understand the middleware' }
// state after dispatch: [ 'Use Redux', 'Understand the middleware' ]
未完待续
本文浅尝applyMiddleware的源码,梳理其中几个函数的关系。但applyMiddleware的独特魅力在于以极少的代码便实现了一个洋葱圈模型。
下一篇将解剖洋葱圈,深入探究其实现原理。