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外,接受一個函數做爲參數。

相關文章
相關標籤/搜索