Middleware是什么
Middleware 只是包装了 store 的 dispatch 方法。技术上讲,任何 middleware 能做的事情,都可能通过手动包装 dispatch 调用来实现,但是放在同一个地方统一管理会使整个项目的扩展变的容易得多。
重新包装 dispatch 方法
为什么要重新包装 dispatch
中间件的作用可以让我们决定什么时候调用dispatch
,可能在promise
函数执行完或在action
里面执行回调函数后,这就需要对旧的dispatch
函数进行重新包装,让它能够先执行中间件函数里面的方法,并把真正的dispatch
传递給中间件函数:
let storeDispatch = stroe.dispatch;// 取出store的dispatch方法保存
// 重写dispatch方法
stroe.dispatch = function (action) {
console.log('before dispatch')
stroe.dispatch(action) // 在适当的时候调用真实的dispatch方法
console.log('after dispatch')
}
只有一个中间件
logger中间件
我们可以写一个logger
中间件来进一步了解:
function logger(store){
return (dispatch)=>{
return (action)=>{
console.log("before logger");
store.dispatch(action);
console.log('after logger')
}
}
}
中间件是一个柯里化组合的函数,每个层级都包装有对应的函数参数供我们调用,真正执行的dispatch
方法其实在最后一个返回的函数里面。
applyMiddleware
扯了这么多还没看看真正的applyMiddleware
函数长什么样子:
function applyMiddleware(middlewares) { // @params 中间件数组
return function (createStore) { // @params 创建store函数
return function (reudcer) { // @params reducer
return store; // @return 返回 createStore(reducer)
}
}
}
applyMiddleware
也是一个柯里化组合的函数,不过最终返回的是一个store
,照上面说的,redux
中间件处理的是dispatch
方法,这里也把store
的dispatch
方法重新包装一下:
function applyMiddleware(middleware) {
return function (createStore) {
return function (reudcer) {
let store = createStore(reudcer);
let dispatch = ()=>{throw new Error("dispatch 还不能用,还没改造成next方法")};
dispatch = middleware(store)(store.dispatch); // 改造包装后的dispatch; 对应logger(store)(dispatch)
return {
...store,
dispatch
}
}
}
}
// 根据applyMiddleware需要返回的函数传入对应的值
applyMiddleware(logger)(createStore)(reducer);
这样每次在组件中调用store
的dispatch
方法时,其实调用的是经过中间件logger
包装后的dispatch
:
function dispatch(action){
console.log('before logger')
store.dispatch(action) // 这里才是真实调用store.dispatch;
console.log('after logger')
}
多个中间件
多个中间件的情况比较复杂,需要保证每个中间件方法都能执行,并且能够像洋葱模型一样,dispatch
方法能够在最里面执行:
function applyMiddleware(...middlewares) {
return function (createStore) {
return function (reudcer) {
const store = createStore(reudcer)
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args),
}
// 将中间件函数先遍历,执行里面的方法并返回,得到一个dispatch方法的中间件数组
const chain = middlewares.map((middleware) => middleware(middlewareAPI))
// compose函数会将包含了dispatch方法的中间件数组组合成一个嵌套的包装函数返回
const dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch,
}
}
}
}
这里compose
方法把中间件里面的dispatch
方法给包装到了一起,让中间件能够一层层往里执行:
//compose
function compose(...funcs) {
if (funcs.length === 0) {
return (args) => args
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, next) => (...args) => a(next(...args)))
}
这里的reduce
不好理解,把它拆成函数,可能会好理解一点:
function compose(...middlewarw) {
return function(storeDispatch) {
function dispatch(index, action) {
let fn = middlewarw[index]
// 回调里面的 next 方法,执行的是下一个中间件函数
let next = () => dispatch(index + 1, action)
// 如果还有下一个中间件就继续执行,并把action传进去,否则执行store.dispatch方法
fn ? fn(next)(action) : storeDispatch(action)
}
return (action) => dispatch(0, action)
}
};
常用中间件
另外常用到的中间件,这里也写下它的源码实现:
redux-thunk
function createThunkMiddleware(extraArgument) {
return ({dispatch,getState}) => next => action => {
if (typeof action == 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
}
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
redux-promise
function isPromise(obj) {
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
}
export default function promiseMiddleware({ dispatch }) {
return next => action => {
return isPromise(action.payload)
? action.payload
.then(result => dispatch({ ...action, payload: result }))
.catch(error => {
dispatch({ ...action, payload: error, error: true });
return Promise.reject(error);
})
: next(action);
};
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。