We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在业务中需要打印每一个 action 信息来调试,又或者希望 dispatch 或 reducer 拥有异步请求的功能。面对这些场景时,一个个修改 dispatch 或 reducer 代码有些乏力,我们需要一个可组合的、自由增减的插件机制,Redux 借鉴了 Koa 中 middleware 的思想,利用它我们可以在前端应用中便捷地实现如日志打印、异步请求等功能。
比如在项目中,进行了如下调用后,redux 就集成了 thunk 函数调用以及打印日志的功能。
import thunk from 'redux-thunk' import logger from '../middleware/logger' const enhancer = applyMiddleware(thunk, logger), // 以 redux-thunk、logger 中间件为例介绍中间件的使用 const store = createStore(rootReducer, enhancer)
下面追本溯源,来分析下源码。
export default function createStore(reducer, preloadedState, enhancer) { // 通过下面代码可以发现,如果 createStore 传入 2 个参数,第二个参数相当于就是 enhancer if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } if (typeof enhancer !== 'undefined') { return enhancer(createStore)(reducer, preloadedState) } ... }
由上述 createStore 源码发现,applyMiddleware 会进行 applyMiddleware(thunk, logger)(createStore)(reducer, preloadedState) 的调用。
applyMiddleware(thunk, logger)(createStore)(reducer, preloadedState)
applyMiddleware 源码如下
export default function applyMiddleware(...middlewares) { return createStore => (...args) => { const store = createStore(...args) let dispatch = store.dispatch let chain = [] const middlewareAPI = { getState: store.getState, // 调用 redux 原生方法,获取状态 dispatch: (...args) => dispatch(...args) // 调用 redux 原生 dispatch 方法 } // 串行 middleware chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch // 返回加工过的 dispatch } } }
可以发现 applyMiddleware 的作用其实就是返回加工过的 dispatch,下面会着重分析 middlewares 是如何串行起来的以及 dispatch 是如何被加工的。
const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
观察上述代码后发现每个 middleware 都会传入参数 middlewareAPI,来看下中间件 logger 的源码 以及 redux-thunk 的源码, 发现中间件接受的第一个参数正是 ({ dispatch, getState })
// logger 源码 export default ({ dispatch, getState }) => next => action => { console.log(action) return next(action) // 经 compose 源码分析,此处 next 为 Store.dispatch }
// redux-thunk 源码 export default ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch) } return next(action) // 此处 next 为 logger 中间件返回的 (action) => {} 函数 }
接着上个小节,在 dispatch = compose(...chain)(store.dispatch) 中发现了 compose 函数,来看下 compose 的源码
dispatch = compose(...chain)(store.dispatch)
export default function compose(...funcs) { // ... return funcs.reduce((a, b) => (...args) => a(b(...args))) }
compose 源码中的 funcs.reduce((a, b) => (...args) => a(b(...args))) 算是比较重要的一句,它的作用是返回组合参数后的函数,比如 compose(f, g, h) 等价于 (...args) => f(g(h(...args))),效果图如下所示,调用 this.props.dispatch() 后,会调用相应的中间件,最终会调用 redux 原生的 store.dispatch(),并且可以看到中间件调用的形式类似数据结构中的栈(先进后出)。
funcs.reduce((a, b) => (...args) => a(b(...args)))
拿上个小节提到的 logger、redux-thunk 中间件为例,其 middleware 的内部串行调用方式如下,从而完成了 dispatch 功能的增强(支持如 this.props.dispatch(func) 的调用以及日志功能)。具体可以看 项目中的运用
this.props.dispatch(func)
action => { if (typeof action === 'function') { return action(dispatch) } return (action => { console.log(action) return store.dispatch(action) })(action) }
深入React技术栈
The text was updated successfully, but these errors were encountered:
No branches or pull requests
middleware 的由来
在业务中需要打印每一个 action 信息来调试,又或者希望 dispatch 或 reducer 拥有异步请求的功能。面对这些场景时,一个个修改 dispatch 或 reducer 代码有些乏力,我们需要一个可组合的、自由增减的插件机制,Redux 借鉴了 Koa 中 middleware 的思想,利用它我们可以在前端应用中便捷地实现如日志打印、异步请求等功能。
比如在项目中,进行了如下调用后,redux 就集成了 thunk 函数调用以及打印日志的功能。
下面追本溯源,来分析下源码。
applyMiddleware 调用入口
由上述 createStore 源码发现,applyMiddleware 会进行
applyMiddleware(thunk, logger)(createStore)(reducer, preloadedState)
的调用。applyMiddleware 源码如下
可以发现 applyMiddleware 的作用其实就是返回加工过的 dispatch,下面会着重分析 middlewares 是如何串行起来的以及 dispatch 是如何被加工的。
串行 middleware
观察上述代码后发现每个 middleware 都会传入参数 middlewareAPI,来看下中间件 logger 的源码 以及 redux-thunk 的源码, 发现中间件接受的第一个参数正是 ({ dispatch, getState })
dispatch 是如何被加工的
接着上个小节,在
dispatch = compose(...chain)(store.dispatch)
中发现了 compose 函数,来看下 compose 的源码compose 源码中的
funcs.reduce((a, b) => (...args) => a(b(...args)))
算是比较重要的一句,它的作用是返回组合参数后的函数,比如 compose(f, g, h) 等价于 (...args) => f(g(h(...args))),效果图如下所示,调用 this.props.dispatch() 后,会调用相应的中间件,最终会调用 redux 原生的 store.dispatch(),并且可以看到中间件调用的形式类似数据结构中的栈(先进后出)。拿上个小节提到的 logger、redux-thunk 中间件为例,其 middleware 的内部串行调用方式如下,从而完成了 dispatch 功能的增强(支持如
this.props.dispatch(func)
的调用以及日志功能)。具体可以看 项目中的运用参考文献
深入React技术栈
The text was updated successfully, but these errors were encountered: