摘要:上一篇文章講解了如何使用,本篇文章將進一步深入,從的源碼入手,深入學習的中間件機制。的功能是讓支持異步,讓我們可以在中跟服務器進行交互等操作,而他的實現。。。
上一篇文章講解了redux如何使用,本篇文章將進一步深入,從redux的源碼入手,深入學習redux的中間件機制。
在這里我們會以一個redux-thunk中間件為例,逐步分解redux的中間機制如何操作,如何執行。
閑話不多說,上代碼。
如何加載中間件import { createStore, applyMiddleware } from "redux"; import thunk from "redux-thunk"; import rootReducer from "./reducers/index"; // create a store that has redux-thunk middleware enabled const createStoreWithMiddleware = applyMiddleware( thunk )(createStore); const store = createStoreWithMiddleware(rootReducer);
這里需要用到redux中提供的一個工具方法,叫做applyMiddleware,向該方法傳入你想要使用的中間件,完了之后再傳入createStore方法,
最終形成新的創建store的方法。
這顯然是一個裝飾器模式,通過不同的中間件對createStore方法進行修飾,最后形成新的createStore方法,那么創建的store就具有這些中間件的特性,
非常出色的設計,驚喜不僅在這,看了之后的代碼你就更不得不佩服作者的代碼設計能力。
瞬間覺得別人都是碼神,而我就是碼農有木有/(ㄒoㄒ)/~~
中間件加載機制的實現先來看applyMiddleware方法的實現
import compose from "./compose"; /** * Creates a store enhancer that applies middleware to the dispatch method * of the Redux store. This is handy for a variety of tasks, such as expressing * asynchronous actions in a concise manner, or logging every action payload. * * See `redux-thunk` package as an example of the Redux middleware. * * Because middleware is potentially asynchronous, this should be the first * store enhancer in the composition chain. * * Note that each middleware will be given the `dispatch` and `getState` functions * as named arguments. * * @param {...Function} middlewares The middleware chain to be applied. * @returns {Function} A store enhancer applying the middleware. */ export default function applyMiddleware(...middlewares) { return (next) => (reducer, initialState) => { var store = next(reducer, initialState); var dispatch = store.dispatch; var chain = []; var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) }; chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); return { ...store, dispatch }; }; }
這就是redux里面這個方法的源碼,其中還一半是注釋有木有。。。本來以為肯定有百來行代碼的
當然這里不得不說es6的特性提供了非常多的幫助,所以為了省力吧es6玩透還是灰常有必要的(更別說為了裝X了(^__^) )
從這里開始代碼就有點繞了,我們逐行分析
return (next) => (reducer, initialState) => {...}
整個applyMiddleware方法就是返回了一個方法,根據applyMiddleware方法的使用,我們可以知道next就是createStore方法,
因為最終我們要返回的是一個裝飾過的createStore方法,那么接收的參數肯定是不會變,所以最終我們調用createStoreWithMiddleware方法其實就是調用
function (reducer, initialState) { var store = next(reducer, initialState); // next即為最初的createStore方法 // ...以下省略 }
var store = next(reducer, initialState); var dispatch = store.dispatch; var chain = [];
這里沒什么好講的,首先創建了一個store,這個store就是最原始的通過createStore創建的store,后兩行只是變量賦值
var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) }; chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch);
這里是關鍵,必須詳細進行講解。
首先,這邊聲明了一個middlewareAPI對象,這個對象包含兩個方法:
getState:store中的getState方法的引用
dispatch:對本身的dispatch方法進行一次封裝
然后
chain = middlewares.map(middleware => middleware(middlewareAPI));
我們來仔細看看這行代碼,首先我們對所有的中間件進行一個map,map結果就是調用中間件方法,將middlewareAPI作為參數傳入,
這里我們拿redux-thunk中間件舉例,來看看一個中間件是長什么樣子的,傳入的參數又是用來干嘛的。
export default function thunkMiddleware({ dispatch, getState }) { return next => action => typeof action === "function" ? action(dispatch, getState) : next(action); }
redux-thunk的功能是讓action支持異步,讓我們可以在action中跟服務器進行交互等操作,而他的實現。。。(⊙﹏⊙)b是的,又是這么幾行代碼。
我們回顧之前的代碼,在map所有中間件的時候我們調用了thunkMiddleware方法,傳入兩個方法dispatch和getState,然后返回了一個方法,
我們大致抽象一下,應該如下:
function (next) { return function (action) { typeof action === "function" ? action(dispatch, getState) : next(action) } }
于是我們接下去分析applyMiddleware里面的代碼,
chain = middlewares.map(middleware => middleware(middlewareAPI));
現在我們知道chain是一個數組,每一項是調用每個中間件之后的返回函數
dispatch = compose(...chain)(store.dispatch);
compose是redux里面的一個幫助函數,代碼如下:
export default function compose(...funcs) { return arg => funcs.reduceRight((composed, f) => f(composed), arg); }
~~(>_<)~~我已經不想再吐槽什么了,
我們看到這邊先調用了compose函數,傳入了結構后的chain數組,然后compose函數返回的也是一個函數:
function (arg) { return funcs.reduceRight((composed, f) => f(composed), arg); // funcs就是中間件數組 }
然后我們把store.dispatch函數作為arg傳入這個結果,這里reduceRight可以參考這里
。那么這邊得到的結果是什么呢?
// 假設中間件數組是[A, B, C] // 那么結果就是A(B(C(store.dispatch)))
再次結合redux-thunk來看,我們假設只有一個中間件,那么最終的dispatch方法就是
function (action) { typeof action === "function" ? action(dispatch, getState) : next(action) } // 這里的next方法,就是真正的store.dispatch方法 // 這里的dispatch是(action) => store.dispatch(action)
我們再結合redux-thunk的使用方法來分析一下,
function incrementAsync() { return dispatch => { setTimeout(() => { // Yay! Can invoke sync or async actions with `dispatch` dispatch(increment()); }, 1000); }; }
這是使用redux-thunk時可以定義的異步action,我們觸發action的時候調用的是
dispatch(incrementAsync())
incrementAsync返回的是
function (dispatch) { setTimeout(() => { // Yay! Can invoke sync or async actions with `dispatch` dispatch(increment()); }, 1000); }
這個時候我們回想經過中間件加工的dispatch方法:
function (action) { typeof action === "function" ? action(dispatch, getState) : next(action) } // 這里的next方法,就是真正的store.dispatch方法 // 這里的dispatch是(action) => store.dispatch(action)
action是一個函數,所以action === "function" ?成立,那么就執行action, 并把中間件接收到的dispatch方法((action) => store.dispatch(action))方法作為參數傳入,在異步方法執行完之后再次觸發真正的action。如果action不是異步的,那么久直接返回一個對象,這個時候action === "function" ?不成立,就直接調用next,也就是原始的store.dispatch方法。
我們再接著想,如果我們有許多個中間件,那么沒一個中間件的next就是下一個中間件直到最后一個中間件調用store.dispatch為止。
以上的代碼非常繞,建議去專研一下源碼。這么精簡的代碼包含了非常多的函數式編程的思想,也用到了裝飾器模式的原理,不得不說:
太燒腦啦/(ㄒoㄒ)/~~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78911.html
摘要:因為工作中一直在使用,也一直以來想總結一下自己關于的一些知識經驗。于是把一些想法慢慢整理書寫下來,做成一本開源免費專業簡單的入門級別的小書,提供給社區。本書的后續可能會做成視頻版本,敬請期待。本作品采用署名禁止演繹國際許可協議進行許可 React.js 小書 本文作者:胡子大哈本文原文:React.js 小書 轉載請注明出處,保留原文鏈接以及作者信息 在線閱讀:http://huzi...
摘要:在項目中用好高階組件,可以顯著提高代碼質量。高階組件的定義類比于高階函數的定義。高階函數接收函數作為參數,并且返回值也是一個函數。 React 深入系列,深入講解了React中的重點概念、特性和模式等,旨在幫助大家加深對React的理解,以及在項目中更加靈活地使用React。 1. 基本概念 高階組件是React 中一個很重要且比較復雜的概念,高階組件在很多第三方庫(如Redux)中都...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數,也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...
閱讀 3039·2021-09-08 10:43
閱讀 1036·2019-08-30 15:53
閱讀 980·2019-08-30 13:51
閱讀 845·2019-08-29 14:03
閱讀 803·2019-08-26 18:35
閱讀 1234·2019-08-26 13:38
閱讀 1584·2019-08-26 10:34
閱讀 3503·2019-08-26 10:21