Redux源码分析:
- Redux源码分析--Middleware(1)
- Redux源码分析--Middleware(2)
- Redux源码分析--Enhancer
- Redux源码分析--createStore(dispatch、getState)
- Redux源码分析--CreateStore(subscribe)
- Redux源码分析--compose
Middleware可以意为中间件,Reudx middleware作用于dispatch,丰富了dispatch的功能,也可以认为是store enhancer(store增强器)。Redux Middleware主要工作在action发起之后,到达reducer之前。
Redux middleware主要解决:进行日志记录、异步请求、创建崩溃报告等
Redux middleware实现模式:
({getState, dispatch}) => (next) => (action) => {}
下面分析下applyMiddleware.js源码
export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
上面是applyMiddleware.js所有源码,就聊聊十几行,为了更好分析源码,我们先分析下下面两个问题
一、解释下为啥middleware的实现模式为() => () => () => {}
- 从代码const chain = middlewares.map(middleware => middleware(middlewareAPI))中,我们知道,在这里,middleware将执行一次,并将{getState, dispatch}作为参数传入,因此我们写middleware模式时,是({getState, dispatch}) => ...
- 对于dispatch = compose(...chain)(store.dispatch),compose是将一系列函数组合成一个函数,如果你想了解compose,请跳转至compose介绍。store.dispatch将作为compose最右边参数函数的参数运行,返回一个函数() => {},赋值给dispatch。因此middleware模式变为({getState, dispatch}) => (next) => ....
- middleware实质是丰富了dispatch功能的enhancer,最后,我们还需要dispatch(action),来进行state的修改,所以说最后还要进行(action) => {}
因此middleware的实现模式为({getState, dispatch}) => (next) => (action) => {}
二、为什么({getState, dispatch}) => (next) => (action) => {}中是next,而不是dispatch,因为我们明明是传入的是store.dispatch
dispatch = compose(...chain)(store.dispatch)中,store.dispatch作为参数传入的只是compose参数中最右边函数,如果是applyMiddleware中传入的最有边的中间件,你可以写成dispatch,但是所有的中间件中,你写成dispatch就不合适了,其实next指向的(action) => {},下面用一个实例来说明:
let m1 = ({ dispatch, getState }) => (next) => (action) => {
console.log('m1');
console.log(next);
return next(action);
}
let m2 = ({ dispatch, getState }) => (next) => (action) => {
console.log('m2');
console.log(next);
return next(action);
}
let store = applyMiddleware(m1, m2)(createStore)(reducer)
m1, m2就是定义的两个中间件,控制台上输出结果:
三、在applyMiddleware.js源码中,为啥是dispatch: (...args) => dispatch(...args)而不是dispatch:dispatch
写成dispatch: (...args) => dispatch(...args)这种形式,可以认为是一个闭包,dispatch将会是一个动态的,毕竟我们会重新给dispatch赋值,dispatch = compose(...chain)(store.dispatch),其实你阅读很多插件源码,都会发现,闭包的使用是一个十分广泛的。下面用一个实例来解释这个问题:
let p = () => {
let d = () => {console.log('start')};
let o = {
d: (args) => d(args)
}
setTimeout(() => {
d = () => {console.log('1秒后...')}
}, 1000);
setTimeout(() => {
//2秒后执行
o.d();
}, 2000);
}
p();
结果返回:1秒后...
如果将d: (args) => d(args)改为d: d,则返回结果变为start
四、dispatch最初定义的抛出异常函数什么时候调用
'Dispatching while constructing your middleware is not allowed. Other middleware would not be applied to this dispatch.'。这是初始dispatch函数的时候,抛出的异常内容。其实使用dispatch还没有进行dispatch = compose(...chain)(store.dispatch)的时候,具体就是在(action) => {}之前,即({getState, dispatch)} => (next) => 的时候。具体说明:
比如:当在({getState, dispatch}) => {}中调用dispatch(action)时
let m1 = ({getState, dispatch}) => {
console.log('m1====', dispatch);
dispatch({type: 'THROW_ERROR'});
return (next) => (action) => {next(action)}
}
let store = applyMiddleware(m1)(createStore)(reducer)
结果:
当({getState, dispatch}) => (next) => {}中调用dispatch(action),一直报相式问题
这个throw Error保证了dispatch = compose(..chain)(store.dispatch)运行结束,即在(action) => {}这一步
这一章主要解决在学习applyMiddleware.js源码时,产生的一系列问题,下一章,将介绍Middleware在运行时的整个详细的过程,及中间件内部代码什么时候运行