createSagaMiddleware
这篇主要讲 createSagaMiddleware 和 middleware.run 这两个 api。
源码位置
core/src/internal/middleware.js
解析
createSagaMiddleware
创建一个 Redux middleware,并将 Sagas 连接到 Redux Store。 这个方法的内部实现就是下方的 sagaMiddlewareFactory 方法。
sagaMiddlewareFactory
createSagaMiddleware 就是 sagaMiddlewareFactory
export default function sagaMiddlewareFactory({ context = {}, channel = stdChannel(), sagaMonitor, ...options } = {}) {
function sagaMiddleware({ getState, dispatch }) {
// ......
}
sagaMiddleware.run = (...args) => {
// ......
}
sagaMiddleware.setContext = props => {
// ......
}
return sagaMiddleware
}
sagaMiddleware
createSagaMiddleware 返回的是一个叫 sagaMiddleware 的方法
sagaMiddleware 就是一个 redux 的 middleware 所以它接收 getState 和 dispatch 两个参数
返回一个高阶方法,这个也是 redux 的 middleware 的要求,在这个高阶函数里面
有对 sagaMonitor 的处理,然后调用了 next(action)
这个没什么可说的
最后执行 channel.put(action)
然后返回 next(action)
的结果。
主要的逻辑就在 channel.put(action)
这里面,这个我们会在 channel 这篇里面详细介绍。
function sagaMiddleware({ getState, dispatch }) {
boundRunSaga = runSaga.bind(null, {
...options,
context,
channel,
dispatch,
getState,
sagaMonitor,
})
return next => action => {
if (sagaMonitor && sagaMonitor.actionDispatched) {
sagaMonitor.actionDispatched(action)
}
const result = next(action) // hit reducers
channel.put(action)
return result
}
}
middleware.run
sagaMiddleware.run
middleware.run 对应的就是 sagaMiddleware.run 这个方法
抛开 dev 的代码,其实就执行了 boundRunSaga(...args)
这行代码,
而 boundRunSaga 是 runSaga 这个方法 bind 了一些前置参数: boundRunSaga = runSaga.bind(null, {// ...})
,所以当你使用 middleware.run(saga, ...args)
去调用时,除了 saga 和 ...args 之外
还给 runSaga 传递了一个 object 里面包含了若干参数。
runSaga 的定义在 runSaga.js 这个文件里面,我们会在 runSaga 这篇里面详细介绍。
boundRunSaga = runSaga.bind(null, {
...options,
context,
channel,
dispatch,
getState,
sagaMonitor,
})
sagaMiddleware.run = (...args) => {
if (process.env.NODE_ENV !== 'production' && !boundRunSaga) {
throw new Error('Before running a Saga, you must mount the Saga middleware on the Store using applyMiddleware')
}
return boundRunSaga(...args)
}