中间件可以说是 Redux
最出色的设计之一了,通过他,我们可以实现很多有用的功能,比如记录日志、记录action历史、实现撤销操作等等。废话不多说,直接操作,在上一节代码的基础上,实现记录日志和识别 Promise
的中间件,先抛开 Redux
实现几个简单版本的中间件
记录日志
创建一个 addLoggingToDispatch
,该方法有接收创建的 store
返回一个新的 dispatch
,实现步骤:
- 记录原来
store.dispatch
; - 在新返回的函数中打印
state
的变化,并调用原dispatch
返回值;
代码
const addLoggingToDispatch = (store) => {
const originDispatch = store.dispatch;
return (action) => {
console.group(action.type)
console.log('start', store.getState());
const result = originDispatch(action);
console.log('end', store.getState());
console.groupEnd(action.type)
return action;
}
}
使用
store.dispatch = addLoggingToDispatch(store);
store.dispatch(action);
识别 Primise
创建 addPromiseSupportToDispatch
,判断传入的 action
是否为 Promise
,是的话将在 then
中处理 dispatch
;
const addPromiseSupportToDispatch = (store) => {
const originDispatch = store.dispatch;
return (action) => {
if (action instanceof Promise) {
action.then(originDispatch);
} else {
originDispatch(action);
return action;
}
}
}
使用
store.dispatch = addPromiseSupportToDispatch(store);
store.dispatch(Promise.resolve(action))
要两个结合使用的话就得注意赋值顺序了,logger
中间件接收到的action 应该是 promise
中间件处理过的action
store.dispatch = addLoggingToDispatch(store);
store.dispatch = addPromiseSupportToDispatch(store);
Redux解决方案:applyMiddleware
上面两个中间件为了方便,并没有按照 Redux
的标准写,现在我们来改装下:
const addPromiseSupportToDispatch = (store) => (next) => (action) => {
if (action instanceof Promise) {
action.then(next);
} else {
next(action);
return action;
}
}
const addLoggingToDispatch = (store) => (next) => (action) => {
console.group(action.type)
console.log('start', store.getState());
const result = next(action);
console.log('end', store.getState());
console.groupEnd(action.type)
return result;
}
next
表示 dispatch
createStore
其实是能接受三个参数
- reducer
- initialState 初始化值
- enhancer
applyMiddleware
返回的函数 在源码中有这么一段代码
这里可以看出 applyMiddleware
的返回值是一个两级柯里化的函数,applyMiddleware
接受若干个中间件
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
承担了创建 store
,并将 store
和 dispatch
分发给各个中间件
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)
}
这里包装这个 middlewareAPI
,并替换掉 store
的 dispatch
,目的是为了在中间件中禁止调用 dispatch
,至于为什么禁止这里已经说明,你直接调用的 dispatch
是没应用到别的中间件的 dispatch
;
compose(...chain)(store.dispatch)
这个就是典型的函数式编程里面的compose
了,实现和各个工具类实现大同小异
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
最后将我们写的两个中间应用到store中
const store = createStore(
rootReducer,
{
name: 'jack',
age: 18,
},
applyMiddleware(addPromiseSupportToDispatch, addLoggingToDispatch),
);
总结
感谢观看,感觉写的有点乱,归纳不足处感谢指正
文中示例代码目录地址:github.com/Yang-yu-don…
系列文章
参考
《React状态管理与同构实战》