索鸟网

  1. 首页
  2. redux中间件探秘

redux中间件探秘


从redux-thunk引出思考

在使用redux-thunk进行异步action书写的时候,我经常好奇redux到底如何运作,让asyncAction成为可能

为了探究,我们必须看一下redux-thunk的源码了。幸运的是redux-thunk的源码很少。。。至于为什么,下面立马讲解。

redux-thunk的源码

// redux-thunk source code
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;

从源码可以看出该中间件仅仅只是一个工厂函数,输出了一个嵌套工厂函数的工厂函数,那个最终参数带着next的返回函数,就是redux所需要适应的中间件。

以es6箭头语法看来可能比较麻烦,我们可以试着把这个代码直接转成es5的形式看看。

function createThunkMiddleware(extraArgument) {
  return function (storeOrFakeStore) {
    var dispatch = storeOrFakeStore.dispatch;
    var getState = storeOrFakeStore.getState;
    return function (next) {
      return function (action) {
          return action(dispatch, getState, extraArgument);
      }
      return next(action);
    }
  };
}

从这个源码可以看出,本身中间件是会接受当前store或者一个fakeStore(这个fakeStore可能仅仅只承载了store的两个api,dispatch和getState),并将dispatch和getState这两个store的方法传进可能执行异步操作的action函数里。这样,action完成异步操作以后,同样被赋予了dispatch的权利,就能够将状态通过action流转到下一个场景了。

那同学们又会问了,这个next是个啥?恩,其实这个next其实就是下一个要处理action的中间件,毕竟中间件是一个接着一个的对吧。如果大家写过koa或者express应该对这个next会熟悉很多。

接下来我们来看看react源码中的createStore模块是怎么应用中间件的。

我们使用createStore api创建store的时候发生了什么

applyMiddleware同样也是一个工厂,如果读者您用过redux中间件的话,你应该知道redux创建store是怎样创建的

const store = createStore(
  reducer,
  applyMiddleware(...middleware)
)

以下是createStore的源码,我们只看相关的一部分

export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)
  }
  ...
}

结合store的声明和使用,我们可以知道redux的第三个参数可以接受一个叫做增强器的东西,如果存在增强器,则直接调用增强器方法,返回新的store并增强redux的功能。而使用中间件的时候,redux将存在的applyMiddleware工厂方法作为增强器应用在了redux上。

applyMiddleware api如何实现中间件操作的。

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
    }
  }
}

applyMiddleware工厂函数对传入的中间件进行了compose操作,使中间件互相之间呈嵌套的形式,这样在中间件里的next函数就可以next()执行下去了。。。新的dispatch会从第一个中间件开始触发,这样,在我们调用store.dispatch的时候,就会将中间件走一遍了。

// compose函数
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }
  // 如果存在多个中间件,直接使用reduce方法将各个中间件嵌套起来。
  // 于是我们在使用中间件的时候就要注意了,中间件本质是一个拦截操作
  // 如果我们有两个中间件对某一个类型的action先后做了拦截,我们必须注意
  // 在createStore的时候插入中间件的顺序,中间件方法的执行是有序的。
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

你也可以制作一个中间件

怎么样,redux的源码简单吗?简单到同学们也能自己开发中间件,现在大家自己也可以动手写自己的react中间件了。

redux 源代码 javascript

来源地址:https://segmentfault.com/a/1190000010433373 版权归作者所有!

相关教程

  • Redux中间件与异步操作

    基本流程 1.创建store,带有三个方法:store.dispatch,store.subscribe,store.getState import { applyMiddleware ,createStore } from "redux"; const store = createStore( reducer, applyMiddlew
  • redux深入理解之中间件(middleware)

    本文代码请看本人github,https://github.com/Rynxiao/redux-middleware 关于redux运用,请看之前一篇文章http://blog.csdn.net/yuzhongzi81/article/details/51880577 理解reduce函数 reduce() 方法接收一个函数作为累加器(accumulator),数组中
  • 【全栈React】第21天: Redux中间件

    本文转载自:众成翻译译者:iOSDevLog链接:http://www.zcfy.cc/article/3810原文:https://www.fullstackreact.com/30-days-of-react/day-21/ 今天,我们在Redux方法中使用Redux中间件来管理我们的代码中的复杂状态变化。 昨天, 我们连接的点与Redux, 从工作
  • Redux中间件对闭包的一个巧妙使用

    最近在看Redux的源码,发现Redux在使用中间件applyMiddleware.js的源码中,有一个对闭包非常巧妙的使用,解决了“鸡生蛋,蛋生鸡”的问题,特分享给大家。 Redux中间件的函数签名形式如下: ({dispatch, getState}) => next => action => { // 函数体 } appl
  • JavaScript的事件探秘

    一、事件流 事件流描述的是从页面中接受事件的顺序。 IE的事件流是事件冒泡流,而Netscape的事件流是事件捕获流 1、事件冒泡 事件冒泡,即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上转播至最不具体的节点(文档)。 如下图所示,如果你点击了按钮,那么也认为你点击了外面的div,最终会一直传递到document上,从小到大的传播,就好比水
  • React Redux 中间件思想遇见 Web Worker 的灵感(附demo)

    写在最前 原文首发于作者的知乎专栏:React Redux 中间件思想遇见 Web Worker 的灵感(附demo),感兴趣的同学可以知乎关注,进行交流。 熟悉 React 技术栈的同学,想必对 Redux 数据流框架并不陌生。其倡导的单向数据流等思想独树一帜,虽然样板代码会有一定程度上的增多,但是对于开发效率和调试效率的提高是显著的。同时还带来了很多
  • 中间件为何不起作用——中间件的位置

    Route::group(["middleware" => ["web"]], function () { Route::get("code","Admin\LoginController@code"); Route::any("login","Admin\LoginController@login"); }); Route::group(["middleware
  • Redux概念之一: Redux简介

    Redux的官网中用一句话来说明Redux是什么: Redux是针对JavaScript应用的可预测状态容器 这句话虽然简短,其实是有几个涵义的: 可预测的(predictable): 因为Redux用了reducer与纯函数(pure function)的概念,每个新的state都会由旧的state建来一个全新的state,这样可以作所谓的时光旅行调试。因此,所