共计 3399 个字符,预计需要花费 9 分钟才能阅读完成。
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);
};
}