资讯专栏INFORMATION COLUMN

redux中间件探秘

Jeff / 1268人阅读

摘要:接下来我们来看看源码中的模块是怎么应用中间件的。如何实现中间件操作的。新的会从第一个中间件开始触发,这样,在我们调用的时候,就会将中间件走一遍了。函数如果存在多个中间件,直接使用方法将各个中间件嵌套起来。

从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中间件了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84517.html

相关文章

  • React Render Array 性能大乱斗

    摘要:现在关于最新版本新特性的宣传讲解已经铺天盖地了。测试场景是反复操作数组,这个反复操作有所讲究,我们计划持续不断地改变数组的某一项而不是整个数组的大范围变动。代码和性能测试在使用开发时,相信很多开发者在搭配函数式的状态管理框架使用。 现在关于 React 最新 v16 版本新特性的宣传、讲解已经铺天盖地了。你最喜欢哪一个 new feature?截至目前,组件构建方式已经琳琅满目。那么,...

    wenshi11019 评论0 收藏0
  • React 内部机制探秘 - React Component 和 Element(文末附彩蛋demo

    摘要:内部机制探秘和文末附彩蛋和源码这篇文章比较偏基础,但是对入门内部机制和实现原理却至关重要。当然也需要明白一些浅显的内部工作机制。当改变出现时,相比于真实更新虚拟的性能优势非常明显。直到最终,会得到完整的表述树的对象。 React 内部机制探秘 - React Component 和 Element(文末附彩蛋demo和源码) 这篇文章比较偏基础,但是对入门 React 内部机制和实现原...

    wenshi11019 评论0 收藏0
  • 前端每周清单半年盘点之 React 与 ReactNative 篇

    摘要:前端每周清单半年盘点之与篇前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点分为新闻热点开发教程工程实践深度阅读开源项目巅峰人生等栏目。与求同存异近日,宣布将的构建工具由迁移到,引发了很多开发者的讨论。 前端每周清单半年盘点之 React 与 ReactNative 篇 前端每周清单专注前端领域内容,以对外文资料的搜集为主,帮助开发者了解一周前端热点;分为...

    Barry_Ng 评论0 收藏0
  • 2017-09-30 前端日报

    摘要:前端日报精选刘海打理指北中的错误处理模式与反模式译图解和译你并不知道中文装饰器让你的代码更简洁众成翻译第期每个程序员第一份工作前应该知道的件事中的不变性众成翻译写的一次小结掘金内部机制探秘和文末附彩蛋和源码前端杂谈开发实战 2017-09-30 前端日报 精选 iPhone X 刘海打理指北React16中的错误处理ES6 Promise:模式与反模式「译」图解 ArrayBuffer...

    darryrzhong 评论0 收藏0
  • JavaScript 工作原理之十五-类和继承及 Babel 和 TypeScript 代码转换探秘

    摘要:使用新的易用的类定义,归根结底也是要创建构造函数和修改原型。首先,它把构造函数当成单独的函数且包含类属性集。该节点还储存了指向父类的指针引用,该父类也并储存了构造函数,属性集和及父类引用,依次类推。 原文请查阅这里,略有删减,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland。 本系列持续更新中,Github 地址请查阅这里。 这是 JavaScript 工作原理的第...

    GeekGhc 评论0 收藏0

发表评论

0条评论

Jeff

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<