深度剖析github star数15.1k的开源项目redux-thunk

徐小夕 等级 802 0 0

日益忙碌的一周又过去了,是时候开始每周一次的总结复盘了,今天笔者就来剖析一下githubstar数15.1k的开源项目redux-thunk

作为一名React方向的前端工程师,不管是被面试还是面试别人,大部分都会说起redux-thunk的实现原理,因为它非常经典且有用,而且代码量少的感人,只有短短12行代码,却能解决React开发中同一个函数支持多dispatch异步action的问题(虽然这完全依赖于redux的中间件机制(Middleware))。

接下来笔者将从:

  • Redux的工作机制
  • 中间件实现原理
  • redux-thunk源码实现

这三个方面来带大家彻底掌握redux-thunk源码,从而对redux有更深入的了解和应用。如果大家对react-redux-redux-thunk实战感兴趣的,读完之后可以移步笔者的《彻底掌握redux》之开发一个任务管理平台

正文

在解读Redux-thunk源码之前我们需要先掌握redux的基本工作机制和中间件实现原理,这样才能更好的理解源码背后的奥义。长话短说我们先来看看redux的几个核心api及其作用: 深度剖析github star数15.1k的开源项目redux-thunk redux解决的真正问题是React组件间的状态共享状态管理问题,通过以上的6个核心api我们便能管理复杂的状态,并能监听和追溯状态的改动。机制笔者总结如下: 深度剖析github star数15.1k的开源项目redux-thunk redux工作机理基本了解之后,我们先看看一个实际的例子:

import actionType from './actionType'

class Actions {
    static start() {
        return {
            type: actionType.CREATE_TODO_DOING
        }
    }

    static ok(data, cb) {
        cb && 'function' === typeof cb && cb(data);
        return {
            type: actionType.CREATE_TODO_SUCCESS,
            payload: data
        }
    }

    static fail(data, cb) {
        cb && 'function' === typeof cb && cb(data);
        return {
            type: actionType.CREATE_TODO_FAILURE,
            payload: data
        }
    }
}

以上代码我们可以发现我们用了一个统一的createAction来创建action,在调用时只需要执行Actions.start()即可,我们也知道action返回的是一个标准的对象,但我们可以在return之前做一些side effect。这里我们并不能在action中处理异步逻辑,这也是redux-thunk的价值之一,即解决异步调用action。

到这一步我们仍然不能直接进入redux-thunk的源码分析,因为我们还是不清楚如何解决上述步骤,因为我们还没有了解redux的中间件机制。

redux中间件机制

说到中间件(middleware),使用过nodejs的人可能会很熟悉,比如说知名的koa中间件,express中间件等,其实中间件笔者的理解是在某个执行流中的某个环节做一些额外的处理的模块。实现中间件的机制也很简单, 就是在框架核心执行流中去遍历外部传入的中间件,并依次执行即可,我们先来看看redux中如何使用中间件的:

import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';

const middlewares = applyMiddleware(middleware1, middleware2);
const store = createStore(reducers, middlewares);

所以说redux-thunk是被传入applyMiddleware方法中作为参数使用的,不难猜到applyMiddleware方法中一定有遍历执行参数的逻辑,我们来看看applyMiddleware的核心源码:

export default function applyMiddleware(...middlewares) {
    return function enhancer(createStore) {
        return function enhancedCreateStore(...args) {
        const store = createStore(...args)
        let dispatch = () => {
            thrownewError('此处省略n个字...')
        }

        const middlewareAPI = {
            getState: store.getState,
          dispatch: (...args) => dispatch(...args)
        }

        const chain = middlewares.map(function(middleware) {
            return middleware(middlewareAPI)
        })

        dispatch = compose(...chain)(store.dispatch)
        return {
            ...store,
          dispatch,
        }
     }
  }
}

由上面的源码可知,在chain这段代码里我们发现其存储的是applyMiddleware方法参数传入getState,dispatch后的调用结果。接下来在dispatch这段代码中出现了compose函数, 熟悉函数式编程的朋友不难猜到其内部肯定是实现批处理chain的函数,并将store.dispatch泵送至其内部。上面源码分析后我们知道每一次执行dispatch时,都会先经过middleware的“洗礼”。

我们再来看看compose函数的内部实现:

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

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce(function(a, b) {
    return function (...args) {
      return a(b(...args))
    }
  })
}

由上面代码可以看出compose最终返回的是一个函数,如果参数大于一时,我们采用reduce将上一个函数返回的结果传给下一个函数参数,以此来实现之间的参数共享和传递,非常经典的设计。

在掌握了redux中间件实现原理之后, 我们再来看redux-thunk源码就非常容易理解了。

redux-thunk源码分析

我们先看看这个github中star数15.1k的源码长啥子:

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;

没错, 这就是redux-thunk的全部源码了,是不是很nice~。在上面的介绍中我们了解到redux中间件机制使得我们可以在中间件中拿到必备的dispatch, getState,并且在执行之前已经调用了两层middleware,此时我们可以解剖一下createThunkMiddleware,在第一次调用createThunkMiddleware是在chain阶段,即上面源码分析的: 深度剖析github star数15.1k的开源项目redux-thunk 所以这里的next也就是第二次调用时的store.dispatch, 为了实现同一函数内能执行多次dispatch,我们会判断如果action为函数,则执行action本身并把必要参数传递给它,否则则直接触发dispatch,这样我们就实现了支持action为函数并且支持异步多dispatch的功能了,读到这还是非常感叹其设计的优雅和简洁,不经让笔者感叹:学好函数式,走遍天下都不怕!

最后笔者准备了一个基于React+redux+redux-thunk的实战项目,github地址:

https://github.com/MrXujiang/redux_OA

感兴趣的可以学习参考一下。

最后

如果想学习更多H5游戏, webpacknodegulpcss3javascriptnodeJScanvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入我们的技术群一起学习讨论,共同探索前端的边界。 深度剖析github star数15.1k的开源项目redux-thunk

更多推荐

收藏
评论区

相关推荐

《彻底掌握redux》之开发一个任务管理平台(上)
前言 redux是上手react开发的必经之路,也是目前react项目中使用的最流行状态管理库。虽然我们不使用redux也可以通过react的state和父子props进行基本的数据通信和项目开发,但是对于一个大型项目而言,往往考虑的更多的是代码结构和组件之间的通信,我们需要一种很优雅且有利于扩展的方式去开发我们的复杂系统,所以这种情况下使用redux是最佳
深度剖析github star数15.1k的开源项目redux-thunk
日益忙碌的一周又过去了,是时候开始每周一次的总结复盘了,今天笔者就来剖析一下github中star数15.1k的开源项目reduxthunk。 作为一名React方向的前端工程师,不管是被面试还是面试别人,大部分都会说起reduxthunk的实现原理,因为它非常经典且有用,而且代码量少的感人,只有短短12行代码,却能解决React开发中同一个函数支持多
2019年20款热门机器学习相关开源项目
**1\. TensorFlow** **Star** 126932 **Watch** 8582 **Fork** 74374 **Github** https://github.com/tensorflow/tensorflow 是一个基于数据流编程(dataflow programming)的符号数学系统,被广泛应用于各类机器学习(m
10 个超好看可视化面板
Web 开发中几乎所有平台都需要一个后台管理,但是从零开发一套后台控制面板并不容易,幸运的是有很多开源免费的后台控制面板可以给开发者使用,那么有哪些优秀的开源免费的控制面板呢?我在 Github 上收集了一些优秀的后台控制面板,并总结得出 Top 10。 **1.** **AdminLTE** ------------------- Github Sta
GitHub Star 10K,让你的网站更炫酷的开源库
![](https://oscimg.oschina.net/oscnet/d965c43d-6fcb-483f-acc0-eb72f2996d21.png) 来源:GitHub精选 Hi!大家好呀!我是你们可爱的喵哥! 现在不少网站都支持了骨架屏,能够在网页数据加载前,展示固定的布局,能够减少用户在进入网页时感受到白屏的不适感。 今天要给大家推荐一
GitHub「有偿刷Star」遭热议,请别赚开源的黑心钱
![](https://oscimg.oschina.net/oscnet/c181999e-d6f7-4595-b25b-2123145bc821.jpg) ![](https://oscimg.oschina.net/oscnet/0478d5b3-f801-430c-a9f5-a2ad0e29d8f2.jpg) 编辑 | 小匀 来
Github Statistics 一个基于 React 的 GitHub 数据统计工具
![GitHub](https://user-images.githubusercontent.com/56643819/71428867-87327100-26fe-11ea-8769-11be8fd257f8.png) V 站曾经有个热帖说为何我的开源项目只有 Fork 没有 Star,楼下有个热评说开源项目关注的不应该是 Commit 数据吗?先不论
Github上Laravel开源排行榜Star数31
Github上Laravel开源排行榜Star数31-60名,罗列所有 Laravel 开源扩展包,含 Github Star 数量,下载数量和项目简介。默认排序是按Star数量从多到少来排 31、[cachethq/cachet](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgith
Github上Laravel开源排行榜Star数前30名
Github上Laravel开源排行榜前30名,罗列所有 Laravel 开源扩展包,含 Github Star 数量,下载数量和项目简介。默认排序是按Star数量从多到少来排 1、[cachethq/cachet](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fgithub.com%2
Golang日志框架之logrus
golang日志库 ========= golang标准库的日志框架非常简单,仅仅提供了print,panic和fatal三个函数对于更精细的日志级别、日志文件分割以及日志分发等方面并没有提供支持。所以催生了很多第三方的日志库,但是在golang的世界里,没有一个日志库像slf4j那样在Java中具有绝对统治地位。golang中,流行的日志框架包括logr
IJPay让支付触手可及
[![Gitee star](https://gitee.com/javen205/IJPay/badge/star.svg?theme=white)](https://gitee.com/javen205/IJPay/stargazers) [![Github start](https://img.shields.io/github/stars/Javen
Jenkins CLI 命令行 v0.0.31
![](https://oscimg.oschina.net/oscnet/f96ca5ed-4d95-4b23-9094-b093a70153c0.png) ------------------------------------------------------------------------------- 截止到编辑本文时: > GitHub
Redux入门到使用。
#### ![](https://oscimg.oschina.net/oscnet/c7b0cf8db4ed63eccfdfe3b7d711ec72da6.gif)简介 Redux是针对JavaScript应用的可预测状态容器。 > 如果熟悉设计模式之观察者模式理解起来就简单了。就是将你在其他组件中需要用到的数据放到一个容器中,那么组件就可以从其中取放
Redux入门实战——todo
1.前言 ==== 在之前的博客中,我写了一篇关于todo-list实现的博客,一步一步详细的记录了如何使用基础的React知识实现一个React单页面应用,通过该篇文章,能够对React入门开发有一个直观的认识和粗浅的理解。 近期,个人学习了一下Redux,又将该项目使用 React+Redux的方式进行了实现。本片内容记录以下实践的过程。通过本实例,
taro 知识点
* taro 的包: 包名 说明 @tarojs/redux Redux for Taro @tarojs/redux-h5 Forked react-redux for taro @tarojs/plugin-csso Taro压缩CSS文件 ### 内置环境变量 `process.env.TARO_ENV`用于判断当前编译类型,目