Skip to content

理解 redux 中间件 #7

@Weiting-Zhang

Description

@Weiting-Zhang

最近一直在写 React-Native 相关的东西,项目中用的是 redux 和一些中间件作为状态管理方案,于是梳理了下 redux middleware 相关的东西,简单记录一下~方式是以一个例子开始,再结合相关源码介绍一下 applyMiddleware 及 redux enhancer 的原理。

在 redux 里我们都知道 dispatch 一个 action 会到达 reducer,而 middleware 就是为我们提供 action 被发起之后,到达 reducer 之前的扩展点,比如记录日志📝,创建崩溃报告,调用异步接口等。
一般一个 middleware 的签名是这样的:
({ getState, dispatch }) => next => action => any,(这里的 any 一般是 action 本身)举个🌰,一个能在 store dispatch 时自动 logger 的 middleware 如下所示:

function logger({ getState }) {
  return (next) => (action) => {
    console.log('will dispatch', action)

    // 调用 middleware 链中下一个 middleware 的 dispatch。
    let returnValue = next(action)

    console.log('state after dispatch', getState())

    // 一般会是 action 本身,除非
    // 后面的 middleware 修改了它。
    return returnValue
  }
}
const store = createStore(
  todos,
  [ 'Use Redux' ],
  applyMiddleware(logger)
)

store.dispatch({
  type: 'ADD_TODO',
  text: 'Understand the middleware'
})
// (将打印如下信息:)
// will dispatch: { type: 'ADD_TODO', text: 'Understand the middleware' }
// state after dispatch: [ 'Use Redux', 'Understand the middleware' ]

这个 middleware 是怎么作用到我们的 store 的呢?next 又代表着什么含义呢?
简单看下原理,applyMiddleware 内部的实现大致是这样:

// 非 applyMiddleware 源码 只不过方便理解
// @param middlewares
// @return createStore => createStore
function applyMiddleware(middlewares) {
  // 返回一个 store enhancer
  return (createStore) => { // store enhancer 接收一个 createStore 为参数
    // 返回一个加强过的 createStore
    return (...args) => {
        const store = createStore(...args);
        let dispatch = store.dispatch;
        middlewares = middlewares.slice()
        // 将 middllewares 从右向左排列
        middlewares.reverse()
        middlewares.forEach(middleware =>
          // 重写上一个经过 middleware 的 dispatch
          // 第一个 middleware 会处理 store 原始的 dispatch
          dispatch = middleware(store)(dispatch)
        )
        // 返回经过重新组合过的 store
        return Object.assign({}, store, { dispatch })
    }
  }
}

而 applyMiddleware 最终是通过作为 createStore 时的 enhancer 来影响 store 的,enhancer 相关的源码如下,它的签名是 createStore => createStore

// redux createStore 部分源码
function createStore (reducer, preloadedState, enhancer) {
    if (typeof enhancer !== 'undefined') {
        if (typeof enhancer !== 'function') {
          throw new Error('Expected the enhancer to be a function.')
        }
    return enhancer(createStore)(reducer, preloadedState)
  }
  // some other codes
}

梳理一下:

  1. applyMiddleware 应用 middlewares 生成 store enhancer,enhancer 是一个输入输出都是 createStore 的函数,会代替原生的 createStore 去创建我们最终的 store
  2. enhancer 生成的是加强过的 createStore,怎么加强的呢?可以看 applyMiddleware 返回的 enhancer 函数中返回的新 createStore,他先是利用原生的 createStore 生成一个正常的 store,并且拿到它的 dispatch 方法,然后对传入 middlewares 从右向左排列,用上一个 middleware(store)(dispatch) 生成的 dispatch 去复写 dispatch,最终的 dispatch 类似经过了这样的包装:dispatchFinal = middleware1(store) (middleware2(store)(middleware3(store)(middleware4(store)(dispatchInitial)))),然后代替原生的 dispatch 作为 store 的成员返回给调用方
  3. 从 2 可以看到,middleware 需要实现的功能是:利用 store 和上一个经过修饰的 dispatch 生成新的 dispatch 。在生成新的 dispatch 的过程中,我们可以加上很多功能,当然也可以干掉很多功能(直接拦截),比如我们一开始提到的 logger middleware 先是打印出 action 的内容,再调用上一个 dispatch 做了一下 action 分发(执行 next 函数),可以想象,next 里面又会去调用它的上一个 dispatch(如果没有,则是调用原生的 diaptch),等 next 的调用结束后,logger 则继续执行他的下一步:打印当前 state 的值和返回 next 函数执行的返回值。这是一个经典的”洋葱模型“。
  4. middleware 中的参数 next 实际上可以理解为”上一个 dispatch" ,即被 applyMiddleware 包装的 “dispatch 洋葱"中,里面一层的 dispatch

备注:

  1. 上面的 applyMiddleware 的实现非官方实现,只是为了方便理解。源码可见:https://github.com/reduxjs/redux/blob/master/src/applyMiddleware.ts
  2. enhancer 是 redux 的一个很强大的扩展机制,applyMiddleware 只是 enhancer 的冰山一角,它只改变了 store dispatch 的默认行为。其他 enhancer 的例子如: redux-devtools

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions