Redux-thunk快速入门

前言

最近刚刚完成了毕业答辩,个人毕设内容是基于React系列技术栈开发的一个相似Instagram的Web App,戳此看看。开发完后,我惊奇的发现:咦,以前就据说有个叫作redux-thunk的东西,我怎么没用到?业务场景太简单了?因而大概研究了下。。git

概念的基本介绍

关于redux-thunk的基本介绍,也许你能够先看看stackoverflow上面的介绍。我的理解:redux-thunk改写了dispatch API,使其具有接受一个函数做为参数的能力,从而达到middleware的效果,即在redux的dispatch action => reducer => store这个流程中,在action 被发起以后,到达 reducer 以前的扩展点,加入相关操做,好比发生请求、log信息等。github

实际使用

以我本次毕设项目中,在redux流程中加入异步请求为例,为动态点赞功能部分代码实现:redux

  • 原本我是这样写的
//from action.js
const LIKE = (id) => ({
     type: "LIKE",
     id:id
})

reqLike({id:id}).then(res =>{ dispatch(LIKE(id))})
复制代码

能够看到,我在请求之后的回调函数中dispatch action去同步redux store中的状态。app

  • 加入redux-thunk以后我是这样写的:
//from action.js
const LIKE = (id) => {
    return function (dispatch,getState) {
        reqLike({id:id}).then(res =>{ 
            dispatch({
                type: "LIKE",
                id:id
            })
        })
    }
}

dispatch(LIKE(id))
复制代码

改变之后,从功能层面上来讲,二者并没有差异,均可以知足业务场景需求。但除此以外咱们能够发现:异步

  • 1.dispatch接受的参数由一个PlainObject变为一个函数
  • 2.咱们把请求的异步操做从dispatch action这个redux流程外塞到的流程里,这看起来将异步操做内聚到这个流程中,不管是从逻辑上理解(这很middleware!)仍是项目代码开发维护(区分异步与同步状态管理流程进行维护管理)上都是很大的改进
  • 3.若是项目中有多处须要实现点赞功能,咱们能够节省不少冗余代码,不用处处在dispatch外层套上reqLike(id).then(...)

源码解析

了解了redux-thunk的基本概念以及应用后,咱们一块儿看看源码加深下理解吧,源码十分精巧。ide

首先看到redux源码中applyMiddleware的部分,咱们将thunk做为参数传入以后,直接返回了一个函数,这个函数做为enhancer传入redux源码中的createStore函数中。函数

export default function applyMiddleware(...middlewares) {
  //这个返回函数就是enhancer
  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
    }
  }
}
复制代码

在redux源码中的createStore函数中,enhancer被执行,传入参数createStore,又紧接着执行其返回的函数,传入reducer和preloadedState.ui

if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    
    return enhancer(createStore)(reducer, preloadedState)
}
复制代码

接下来,咱们进入applyMiddleware和thunk的关键部分,上面applyMiddleware接受的最初的(...middlewares)参数其实就是thunk,thunk会被执行,而且传入参数getState和dispatch.spa

//传入到thunk的参数
const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
//在map中执行thunk
chain = middlewares.map(middleware =>middleware(middlewareAPI))
//从新改写dispatch
dispatch = compose(...chain)(store.dispatch)
复制代码

那么上面的chain是什么呢,咱们终于能够去看redux-thunk的源码了!code

function createThunkMiddleware(extraArgument) {
  return function (_ref) {
    var dispatch = _ref.dispatch,
        getState = _ref.getState;
    //这里返回的函数就是chain
    return function (next) {
    //这里返回的函数就是改写的dispatch
      return function (action) {
        if (typeof action === 'function') {
          return action(dispatch, getState, extraArgument);
        }

        return next(action);
      };
    };
  };
}

var thunk = createThunkMiddleware();
复制代码

从源码咱们能够看出,chain就是以next做为形参的匿名函数,至于compose只是不断传递每一个函数的返回值给下一个执行函数,而后依次去执行它全部传入的函数而已,它源码中的注释说的很清楚:For example, compose(f, g, h) is identical to doing (...args) => f(g(h(...args))).

咱们这里的chain只是一个函数而已,因此很简单,就是执行chain,而且传入store.dispatch做为next就行。

接下来,进入最后一步,改写了dispatch,最终变为:

function (action) {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }
    //next为以前传入的store.dispatch,即改写前的dispatch
    return next(action);
};
复制代码

若是传入的参数是函数,则执行函数。不然仍是跟以前同样dispatch(PlainObject).

总结

redux-thunk实现了相关异步流程内聚到redux的流程中,实现middleware的功能,也便于项目的开发与维护,避免冗余代码。而实现的方式即是改写redux中的dispatch API,使其能够除PlainObject外,接受一个函数做为参数。

相关文章
相关标签/搜索