redux中间件原理及实现

最近看跟react相关库的源码,越来越发现里面中间件机制的特别重要,各种类库都是基于此封装的功能,比如redux简单的几个函数,却巧妙的实现了中间件创建,组合,调用,下面就一一分析

先看下面最简单的redux使用例子

import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import reducers from './reducer'

const store = createStore(reducers, compose(
    applyMiddleware(thunk),
    window.devToolsExtension ? window.devToolsExtension() : f => f
))

创建中间件

我们从最里面看,这里的thunk就是个满足redux的中间件实现,打开源码看看,createThunkMiddleware利用函数柯里化的特性缓存了三层参数变量,后面调用了才暴露出去的,所以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;

thunk简化后就是, 接受两个参数dispatchgetState, 返回一个函数,继续调用则会传入next就是真正的dispatch的, 这里action一般都是一个对象,比如{type: AUTH_SUCCESS, payload:data}, 就用dispatch(action)去触发变更组件,但是这个中间件判断了一下action是函数function的时候,会调用这个函数,然后把参数传进去

function thunk ({ dispatch, getState }) {
   return next => actioin => {
      if (typeof action === 'function') {
         return action(dispatch, getState);
      }
      return next(action);
  }
}

那么action是函数的时候是怎么样的呢,这就是reudx-thunk实现的功能, 在有异步请求的时候,应该返回一个函数,比如下面, 这就可以在里面继续使用dispatchgetState了,真是煞费苦心啊,就为了实现代码隔离的时候还能够使用redux里面的dispatchgetState来获取状态和触发action实现更新组件

export function login({user, pwd}) {
    return (dispatch, getState) => {
        axios.post('/user/login', {user, pwd})
        .then(res=>{
            if (res.status === 200 && res.data.code === 0){
                dispatch(authSuccess(res.data.data))
            } else {
                dispatch(errorMsg(res.data.msg))
            }
        })
    }
}

使用中间件

上面搞清楚了中间件的创建,那么怎么使用呢,这下就要看applyMiddleware这个函数了,代码如下,也没有几行,可是信息量很大啊,整体来看又是柯里化来保存参数,证明如果有中间件的话,会传入createStore,在这里面构建store,生成每个中间件都需要的dispatchgetState, 接着重点来了,遍历middlewares中间件数组,分别调用每个中间件一次

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)
    return {
      ...store,
      dispatch
    }
  }
}
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }
  if (funcs.length === 1) {
    return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言 最近几天对 redux 的中间件进行了一番梳理,又看了 redux-saga 的文档,和 redux-thu...
    Srtian阅读 33,117评论 9 40
  • “中间件”这个词听起来很恐怖,但它实际一点都不难。想更好的了解中间件的方法就是看一下那些已经实现了的中间件是怎么工...
    Jmingzi_阅读 5,618评论 1 7
  • 一、什么情况需要redux? 1、用户的使用方式复杂 2、不同身份的用户有不同的使用方式(比如普通用户和管...
    初晨的笔记阅读 6,208评论 0 11
  • redux-thunk是什么东西 在此之前先回顾下redux的工作流程:action-> dispatcher -...
    YeLqgd阅读 10,612评论 0 3
  • 1. redux-thunk处理副作用的缺点 1.1 redux的副作用处理 redux中的数据流大致是: UI—...
    Grace_ji阅读 8,884评论 0 14