一般使用了中间件的 redux 初始化是下面这样的
1 | function configureStore(initialState) { |
redux 中间件是一个函数,形式
1 | const middleware1 = store => next => action => { |
需要做到
保证每一个中间件内的 store 引用都是最新的,并且是同一个
连接起来。执行一次 dispatch,会依次执行每一个中间件
代码解释
1 | function applyMiddleWare(...middlerWares) { |
从上面可以看到,一个中间件函数要最后完成,需要再执行前经过两次的初始化(分别传入 store 和 next 方法),然后到最后的调用
- 第一次调用。
1 | const chain = middlerWares.map(middleWare => chain(middlerWareAPI)); |
将store
两个方法传递给中间件,所有中间件内都是同一份store
- 第二步调用也是最关键的地方,就是将所有的中间件串联起来,
dispatch
一次就执行所有的中间件
1 | // 这里其实就是compoose的实现 |
我们知道,经过第一步的初始化,对于middleWare1
函数,可见next
参数就是指向了middleWare2(dispatch)
。只有我们的next
调用了才会执行后面的中间件。而到了最后一个中间件middleWare3
,它的next
参数就是 redux 对应的dispatch
函数了。从而最终把我们的action
派发到store
中去。然后调用栈依次返回。就像一个剥洋葱一样的东西。
所以如果我们把开头的 3 个中间件组合起来运行的话,
输出是
1 | before 1 |
经过上面的代码,我们还可以发现applyMiddleWare
其实也是一个高阶函数。applyMiddleware(middleware1, middleware2, middleware3)
执行后,是一个接收createStore
参数的函数。在createStore
里面又是如何操作的。源码:
1 | function createStore(reducer, preloadedState, enhancer) { |
其实就是把原始的createStore
再传进入,进行创建store
。返回一个更牛逼的store
,这个store
其实只是重写了dispatch
方法。
通过上面一堆分析,有几个结论了:
1、 中间件内部必须调用next
方法。才能调用下一个中间件并且到达 action
2、中间件内部如果调用了dispatch
(重写后的)。不加处理就会死循环,相当于这个洋葱剥到中间又开始剥了。
那么问题来了,dispatch
什么时候用呢?
这就提到一个大名鼎鼎的库redux-thunk
。它的源码里面就是使用了这个dispatch
1 | function createThunkMiddleware(extraArgument) { |
redux-thunk
相信都很熟悉,一般用于处理编写异步逻辑下。它的源码更是牛逼。只有十几行。从上面可以看出它也是一个中间件,它的逻辑就是允许你dispatch
一个函数,当你 dispatch 一个函数的时候,就直接执行它,并传入了dispatch
(注意这个 是 dispatch 不是 前面中间件提到的 next)和getState
方法
1 | const fetchApi = (...args) => (dispatch, getState) => { |
通过前面的分析,传进thunk
内的dispatch
参数就是经过包装的dispatch
,所以当我们去分发一个同步的普通action
的时候,它又能经过我们的其余普通中间件逻辑的处理了
redux
的applyMiddleWare
函数和redux-thunk
。代码很简短,却隐藏着大智慧
- Post title:简析redux技术栈(一):redux中间件
- Post author:flytam
- Create time:2019-08-14 22:34:12
- Post link:https://blog.flytam.vip/简析redux技术栈(一):redux中间件.html
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.