摘要:的存在是為了避免在執(zhí)行過程中,發(fā)生改變,導致錯誤。保證的修改不會影響。在內部關鍵代碼是第一行用來調用,并將執(zhí)行的結果賦給。符合這個標準的會被放入中。以上基本是的全部關鍵代碼剖析,簡單而強大。
前面寫了《React組件性能優(yōu)化》《Redux性能優(yōu)化》《React-Redux性能優(yōu)化》,但是都沒有從這些框架的實現(xiàn)上講為什么?這次就從源碼上來分析一下這些框架的實現(xiàn)原理,以更深入的理解這些框架,并更好的使用它們。
Redux的api很簡單,下面一個一個的分析。
createStore首先說下它的三個參數(shù)reducer、preloadedState、enhancer。reducer是唯一必傳的參數(shù),它很重要,因為它決定了整個state。preloadedState就是state的初始值。第三個參數(shù)不是特別常用,它是個函數(shù),如果它存在的情況下,會執(zhí)行下面的語句:
enhancer(createStore)(reducer, preloadedState)
很顯然enhancer和middleware作用很像,用來增強store。
createStore內部維護了currentReducer(當前的reducer)和currentState(當前的state),初始化的時候:
currentReducer = reducer currentState = preloadedState
這兩個變量很重要,因為很多操作都和它們相關。
subscribe在createStore內部維護了兩個數(shù)組currentListeners、nextListeners。nextListeners的存在是為了避免在listeners執(zhí)行過程中,listeners發(fā)生改變,導致錯誤。listeners的添加或刪除都是對nextListeners進行操作的。
nextListeners = currentListeners.slice()
保證nextListeners的修改不會影響currentListeners。
subscribe(listener)的返回值是個函數(shù),執(zhí)行這個函數(shù)就會unsubscribe(listener),取消監(jiān)聽。
dispatch很重要,因為只能通過它修改state,它只接收一個參數(shù)action,action必須是簡單對象,而且必須有type屬性。在dispatch內部關鍵代碼是:
currentState = currentReducer(currentState, action) var listeners = currentListeners = nextListeners for (var i = 0; i < listeners.length; i++) { listeners[i]() }
第一行用來調用reducer,并將執(zhí)行的結果賦給currentState。這樣currentState中的數(shù)據(jù)就總是最新的,即reducer處理完action之后返回的數(shù)據(jù)。沒有條件,執(zhí)行dispatch后reducer總會執(zhí)行。
后面3行代碼是用來調用subscribe傳進來的listeners,按順序執(zhí)行它們,沒有任何條件判斷,也就是說只要執(zhí)行dispatch,所有的listeners都會執(zhí)行,不管state有沒有發(fā)生改變,而且listeners執(zhí)行的時候是沒參數(shù)的。
Redux內部有個變量
ActionTypes = { INIT: "@@redux/INIT" }
在創(chuàng)建store(即調用createStore(reducer, preloadedState, enhancer))的時候會執(zhí)行
dispatch({ type: ActionTypes.INIT })
所以reducer和listeners在store創(chuàng)建的時候都會被執(zhí)行一遍,listeners沒有什么特別要關注的。reducer執(zhí)行必須關注,因為它的執(zhí)行結果影響你的數(shù)據(jù)。比如createStore的時候你沒有傳入preloadedState,在reducer內的state有默認參數(shù),正常情況下你的reducer會使用default分支處理這個action,而且一般default分支會直接返回state,所以這種情況下store創(chuàng)建完后,使用getState()獲取的值就是默認參數(shù)組成的state。
getState獲取store中的state,很簡單,主要代碼:
return currentState
在沒有dispatch正在執(zhí)行的情況下,直接返回前面說很重要的currentState。
replaceReducer參數(shù)是nextReducer,也很簡單,關鍵代碼:
currentReducer = nextReducer dispatch({ type: ActionTypes.INIT })
直接拿nextReducer替換掉前面說很重要的currentReducer,后面再執(zhí)行dispatch,action就會被nextReducer處理,處理的結果賦值給currentState。替換之后會執(zhí)行一遍初始化action。
combineReducers代碼雖然看起來很長,但是大多都是用來處理校驗reducer的。它接收的參數(shù)reducers是個對象,對象的value不能是undefined,必須是function。符合這個標準的reducer會被放入finalReducers中。
然后再對finalReducers進行校驗,reducer必須有default處理,不能處理Redux內部的action type,比如@@redux/INIT。然后返回一個函數(shù)combination(state = {}, action),它也是一個reducer,可以被再次和其他reducer combine。一般combination等同于currentReducer,它的返回結果會賦給state,combination的關鍵代碼如下:
var finalReducerKeys = Object.keys(finalReducers) var hasChanged = false var nextState = {} for (var i = 0; i < finalReducerKeys.length; i++) { var key = finalReducerKeys[i] var reducer = finalReducers[key] var previousStateForKey = state[key] var nextStateForKey = reducer(previousStateForKey, action) nextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey !== previousStateForKey } return hasChanged ? nextState : state
中間省略了reducer返回結果的校驗。reducer就是通過這種方式從state中拿到對應的state,然后把返回的數(shù)據(jù)組裝到state的對應位置,很巧妙!
bindActionCreators它接收兩個參數(shù)actionCreators和dispatch。如果actionCreators是函數(shù),就直接返回:
(...args) => dispatch(actionCreator(...args))
直接給這個返回的函數(shù)傳actionCreator的參數(shù)就可以直接觸發(fā)dispatch,這也是bindActionCreators的目的,簡化操作,弱化dispatch的存在感。
如果actionCreators是個對象會進行另外的操作,返回一個對象,下面是關鍵代碼。
var keys = Object.keys(actionCreators) var boundActionCreators = {} for (var i = 0; i < keys.length; i++) { var key = keys[i] var actionCreator = actionCreators[key] boundActionCreators[key] = (...args) => dispatch(actionCreator(...args)) } return boundActionCreators
其實里面的處理和單個function的處理是一樣的。
applyMiddleware一個可以被執(zhí)行三次的柯里化函數(shù),代碼雖然簡單,但是給Redux帶來卻是無限可能。它的第一次執(zhí)行的時候參數(shù)是一系列的middlewares,第二次執(zhí)行參數(shù)是createStore,返回的是一個和createStore接收同樣參數(shù)的函數(shù),再次被執(zhí)行的話,就會返回dispatch強化之后的store。關鍵代碼如下:
var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) const last = chain[funcs.length - 1] const rest = chain.slice(0, -1) dispatch = rest.reduceRight((composed, f) => f(composed), last(store.dispatch))
這里只寫了多個middleware的情況,單個middlewares更簡單。代碼很簡單,邏輯也很簡單,作用很大。比如使用thunk可以做異步action。
以上基本是Redux的全部關鍵代碼剖析,Redux簡單而強大。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/90880.html
摘要:為了能夠更好的使用這個工具,今天就對它進行一下源碼剖析。它內部的關鍵代碼是在不指定的時候等于,這就意味著的源碼剖析到此結束,謝謝觀看當然如果指定了剖析就還得繼續(xù)。好了,源碼剖析到此結束,謝謝觀看 React-Redux是用在連接React和Redux上的。如果你想同時用這兩個框架,那么React-Redux基本就是必須的了。為了能夠更好的使用這個工具,今天就對它進行一下源碼剖析。 Pr...
摘要:到月底了,小明的爸爸的單位發(fā)了工資總計塊大洋,拿到工資之后第一件的事情就是上交,毫無疑問的,除非小明爸爸不要命了。當小明的爸爸收到這個通知之后,心的一塊大石頭也就放下來了。下面我們正式開始我們的源碼閱讀之旅。 前言 用過react的小伙伴對redux其實并不陌生,基本大多數(shù)的React應用用到它。一般大家用redux的時候基本都不會單獨去使用它,而是配合react-redux一起去使用...
摘要:的中間件主要是通過模塊實現(xiàn)的。返回的也是一個對象這個其實就是,各個中間件的最底層第三層的哪個函數(shù)組成的圓環(huán)函數(shù)構成的這就是對源碼的一個整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測試例子可以關注源碼解讀倉庫 applyMiddleware源碼解析 中間件機制在redux中是強大且便捷的,利用redux的中間件我們能夠實現(xiàn)日志記錄,異步調用等多種十分實用的功能。redux的中間件主要是...
摘要:表示調用棧在下一將要執(zhí)行的任務。兩方性能解藥我們一般有兩種方案突破上文提到的瓶頸將耗時高成本高易阻塞的長任務切片,分成子任務,并異步執(zhí)行這樣一來,這些子任務會在不同的周期執(zhí)行,進而主線程就可以在子任務間隙當中執(zhí)行更新操作。 showImg(https://segmentfault.com/img/remote/1460000016008111); 性能一直以來是前端開發(fā)中非常重要的話題...
閱讀 3011·2021-11-22 09:34
閱讀 1284·2021-11-19 09:40
閱讀 3423·2021-10-14 09:43
閱讀 3638·2021-09-23 11:22
閱讀 1673·2021-08-31 09:39
閱讀 979·2019-08-30 15:55
閱讀 1489·2019-08-30 15:54
閱讀 920·2019-08-30 15:53