摘要:在得到新的狀態(tài)后,依次調(diào)用所有的監(jiān)聽器,通知狀態(tài)的變更。執(zhí)行完后,獲得數(shù)組,它保存的對象是第二個箭頭函數(shù)返回的匿名函數(shù)。部分源碼利用這個屬性,所有子組件均可以拿到這個屬性。
Redux使用中的幾個點:
Redux三大設(shè)計原則
Create Store
Redux middleware
combineReducer
Provider與Connect
Redux流程梳理
Redux設(shè)計特點
1. Redux三大設(shè)計原則 1. 單一數(shù)據(jù)源在傳統(tǒng)的 MVC 架構(gòu)中,我們可以根據(jù)需要創(chuàng)建無數(shù)個 Model,而 Model 之間可以互相監(jiān)聽、觸發(fā)事件甚至循環(huán)或嵌套觸發(fā)事件,這些在 Redux 中都是不允許的。因為在 Redux 的思想里,一個應(yīng)用永遠只有唯一的數(shù)據(jù)源。
實際上,使用單一數(shù)據(jù)源的好處在于整個應(yīng)用狀態(tài)都保存在一個對象中,這樣我們隨時可以提取出整個應(yīng)用的狀態(tài)進行持久化(比如實現(xiàn)一個針對整個應(yīng)用的即時保存功能)。此外,這樣的設(shè)計也為服務(wù)端渲染提供了可能。
在 Redux 中,我們并不會自己用代碼來定義一個 store。取而代之的是,我們定義一個 reducer,它的功能是根據(jù)當(dāng)前觸發(fā)的 action 對當(dāng)前應(yīng)用的狀態(tài)(state)進行迭代,這里我們并沒有直接修改應(yīng)用的狀態(tài),而是返回了一份全新的狀態(tài)。
Redux 提供的 createStore 方法會根據(jù) reducer 生成 store。最后,我們可以利用 store. dispatch
方法來達到修改狀態(tài)的目的。
在 Redux 里,我們通過定義 reducer 來確定狀態(tài)的修改,而每一個 reducer 都是純函數(shù),這意味著它沒有副作用,即接受一定的輸入,必定會得到一定的輸出。
這樣設(shè)計的好處不僅在于 reducer 里對狀態(tài)的修改變得簡單、純粹、可測試,更有意思的是,Redux 利用每次新返回的狀態(tài)生成酷炫的時間旅行(time travel)調(diào)試方式,讓跟蹤每一次因為觸發(fā) action 而改變狀態(tài)的結(jié)果成為了可能。
2.Create Store我們從store的誕生開始說起。create store函數(shù)API文檔如下:
createStore(reducer, [initialState], enhancer)
可以看出,它接受三個參數(shù):reducer、initialState 和 enhancer 。Store enhancer 是一個組合 store creator 的高階函數(shù),返回一個新的強化過的 store creator。這與 middleware 相似,它也允許你通過復(fù)合函數(shù)改變 store 接口。
再來看看他的返回值:
{ dispatch: f (action), getState: f (), replaceReducer: f (nextReducer), subscribe: f (listener), Symbol(observable): f () }
store的返回值就是一個普通對象,里面有幾個常用的方法:
dispatch:就是我們最常用的dispatch方法,派發(fā)action。
getState:通過該方法,我們可以拿到當(dāng)前狀態(tài)樹state。
replaceReducer:這個方法主要用于 reducer 的熱替換,下面介紹該方法。
subscribe:添加一個變化監(jiān)聽器。每當(dāng) dispatch(action)的時候就會執(zhí)行,state 樹中的一部分可能已經(jīng)變化。
observable:觀察者模式,用于處理訂閱關(guān)系。
這里挑幾個方法介紹:
getState在完成基本的參數(shù)校驗之后,在 createStore 中聲明如下變量及 getState 方法:
var currentReducer = reducer var currentState = initialState var listeners = [] // 當(dāng)前監(jiān)聽 store 變化的監(jiān)聽器 var isDispatching = false // 某個 action 是否處于分發(fā)的處理過程中 /** * Reads the state tree managed by the store. * * @returns {any} The current state tree of your application. */ function getState() { return currentState }
getState方法就是簡單返回當(dāng)前state,如果state沒有被reducer處理過,他就是initialState。
subscribe在 getState 之后,定義了 store 的另一個方法 subscribe:
function subscribe(listener) { listeners.push(listener) var isSubscribed = true return function unsubscribe() { if (!isSubscribed) { return } isSubscribed = false var index = listeners.indexOf(listener) listeners.splice(index, 1) } }
Store 允許使用store.subscribe方法設(shè)置監(jiān)聽函數(shù),一旦 State 發(fā)生變化,就自動執(zhí)行這個函數(shù)。
顯然,只要把 View 的更新函數(shù)(對于 React 項目,就是組件的render方法或setState方法)放入listen,就會實現(xiàn) View 的自動渲染。你可能會感到奇怪,好像我們在 Redux 應(yīng)用中并沒有使用 store.subscribe 方法?事實上,
React Redux 中的 connect 方法隱式地幫我們完成了這個工作。
store.subscribe方法返回一個函數(shù),調(diào)用這個函數(shù)就可以解除監(jiān)聽。
dispatchdispatch是redux的核心方法:
function dispatch(action) { if (!isPlainObject(action)) { throw new Error( "Actions must be plain objects. " + "Use custom middleware for async actions." ) } if (typeof action.type === "undefined") { throw new Error( "Actions may not have an undefined "type" property. " + "Have you misspelled a constant?" ) } if (isDispatching) { throw new Error("Reducers may not dispatch actions.") } try { isDispatching = true currentState = currentReducer(currentState, action) } finally { isDispatching = false } listeners.slice().forEach(listener => listener()) return action }
判斷當(dāng)前是否處于某個 action 的分發(fā)過程中,這個檢查主要是為了避免在 reducer 中分發(fā) action 的情況,因為這樣做可能導(dǎo)致分發(fā)死循環(huán),同時也增加了數(shù)據(jù)流動的復(fù)雜度。
確認當(dāng)前不屬于分發(fā)過程中后,先設(shè)定標志位,然后將當(dāng)前的狀態(tài)和 action 傳給當(dāng)前的reducer,用于生成最新的 state。這看起來一點都不復(fù)雜,這也是我們反復(fù)強調(diào)的 reducer 工作過程——純函數(shù)、接受狀態(tài)和 action 作為參數(shù),返回一個新的狀態(tài)。
在得到新的狀態(tài)后,依次調(diào)用所有的監(jiān)聽器,通知狀態(tài)的變更。需要注意的是,我們在通知監(jiān)聽器變更發(fā)生時,并沒有將最新的狀態(tài)作為參數(shù)傳遞給這些監(jiān)聽器。這是因為在監(jiān)聽器中,我們可以直接調(diào)用 store.getState() 方法拿到最新的狀態(tài)。
最終,處理之后的 action 會被 dispatch 方法返回。
replaceReducerfunction replaceReducer(nextReducer) { if (typeof nextReducer !== "function") { throw new Error("Expected the nextReducer to be a function."); } currentReducer = nextReducer; dispatch({ type: ActionTypes.INIT }); }
這是為了拿到所有 reducer 中的初始狀態(tài)(你是否還記得在定義 reducer 時,第一個參數(shù)為previousState,如果該參數(shù)為空,我們提供默認的 initialState)。只有所有的初始狀態(tài)都成功獲取后,Redux 應(yīng)用才能有條不紊地開始運作。
3.Redux middlewareIt provides a third-party extension point between dispatching an action, and the moment it reaches
the reducer
它提供了一個分類處理 action 的機會。在middleware 中,你可以檢閱每一個流過的 action,挑選出特定類型的action 進行相應(yīng)操作,給你一次改變 action 的機會。
常規(guī)的同步數(shù)據(jù)流模式的流程圖如下:
不同業(yè)務(wù)需求下,比如執(zhí)行action之前和之后都要打log;action觸發(fā)一個異步的請求,請求回來之后渲染view等。需要為這一類的action添加公共的方法或者處理,使用redux middleware流程圖如下:
每一個 middleware 處理一個相對獨立的業(yè)務(wù)需求,通過串聯(lián)不同的 middleware 實現(xiàn)變化多樣的功能。比如上面的業(yè)務(wù),我們把處理log的代碼封裝成一個middleware,處理異步的也是一個middleware,兩者串聯(lián),卻又相互獨立。
使用middleware之后,action觸發(fā)的dispatch并不是原來的dispatch,而是經(jīng)過封裝的new dispatch,在這個new dispatch中,按照順序依次執(zhí)行每個middleware,最后調(diào)用原生的dispatch。
我們來看下logger middleware如何實現(xiàn)的:
export default store => next => action => { console.log("dispatch:", action); next(action); console.log("finish:", action); }
這里代碼十分簡潔,就是在next調(diào)用下一個middleware之前和之后,分別打印兩次。
Redux 提供了 applyMiddleware 方法來加載 middleware,該方法的源碼如下:
import compose from "./compose"; export default function applyMiddleware(...middlewares) { return function (next) { return function (reducer, initialState) { let store = next(reducer, initialState); let dispatch = store.dispatch; let chain = []; var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action), }; chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose(...chain)(store.dispatch); return { ...store, dispatch, }; } } }
其中compose源碼如下:
function compose(...funcs) { return arg => funcs.reduceRight((composed, f) => f(composed), arg); }
使用的時候,如下:
const newStore = applyMiddleware([mid1, mid2, mid3, ...])(createStore)(reducer, initialState);
ok,相關(guān)源碼已就位,我們來詳細解析一波。
函數(shù)式編程思想設(shè)計 :middleware 的設(shè)計有點特殊,是一個層層包裹的匿名函數(shù),這其實是函數(shù)式編程中的
currying,它是一種使用匿名單參數(shù)函數(shù)來實現(xiàn)多參數(shù)函數(shù)的方法。applyMiddleware 會對 logger 這個middleware 進行層層調(diào)用,動態(tài)地將 store 和 next 參數(shù)賦值。currying 的 middleware 結(jié)構(gòu)的好處主要有以下兩點。
易串聯(lián):currying 函數(shù)具有延遲執(zhí)行的特性,通過不斷 currying 形成的 middleware 可以累積參數(shù),再配合組合(compose)的方式,很容易形成 pipeline 來處理數(shù)據(jù)流。
? 共享 store: 在 applyMiddleware 執(zhí)行的過程中,store 還是舊的,但是因為閉包的存在,applyMiddleware 完成后,所有的 middleware 內(nèi)部拿到的 store 是最新且相同的。
給 middleware 分發(fā) store:newStore創(chuàng)建完成之后,applyMiddleware 方法陸續(xù)獲得了3個參數(shù),第一個是 middlewares 數(shù)組[mid1, mid2, mid3, ...],第二個是 Redux 原生的 createStore ,最后一個是 reducer。然后,我們可以看到 applyMiddleware 利用 createStore 和 reducer 創(chuàng)建了一個 store。而 store 的 getState方法和 dispatch 方法又分別被直接和間接地賦值給 middlewareAPI 變量 store:
const middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action), }; chain = middlewares.map(middleware => middleware(middlewareAPI));
然后,讓每個 middleware 帶著 middlewareAPI 這個參數(shù)分別執(zhí)行一遍。執(zhí)行完后,獲得 chain數(shù)組 [f1, f2, ... , fx, ..., fn],它保存的對象是第二個箭頭函數(shù)返回的匿名函數(shù)。因為是閉包,每個匿名函數(shù)都可以訪問相同的 store,即 middlewareAPI。
middlewareAPI 中的 dispatch 為什么要用匿名函數(shù)包裹呢?我們用 applyMiddleware 是為了改造 dispatch,所以 applyMiddleware 執(zhí)行完后,dispatch 是變化了的,而 middlewareAPI 是 applyMiddleware 執(zhí)行中分發(fā)到各個 middleware 的,所以必須用匿名函數(shù)包裹 dispatch,這樣只要 dispatch 更新了,middlewareAPI 中的 dispatch 應(yīng)用也會發(fā)生變化。
組合串聯(lián) middleware:這一層只有一行代碼,卻是 applyMiddleware 精華之所在dispatch = compose(...chain)(store.dispatch); ,其中 compose 是函數(shù)式編程中的組合,它將 chain 中的所有匿名函數(shù) [f1, f2, ... , fx, ..., fn]組裝成一個新的函數(shù),即新的 dispatch。當(dāng)新 dispatch 執(zhí)行時,[f1, f2, ... , fx, ..., fn],從右到左依次執(zhí)行。
compose(...funcs) 返回的是一個匿名函數(shù),其中 funcs 就是 chain 數(shù)組。當(dāng)調(diào)用 reduceRight時,依次從 funcs 數(shù)組的右端取一個函數(shù) fx 拿來執(zhí)行,fx 的參數(shù) composed 就是前一次 fx+1 執(zhí)行的結(jié)果,而第一次執(zhí)行的 fn(n 代表 chain 的長度)的參數(shù) arg 就是 store.dispatch。所以,當(dāng) compose 執(zhí)行完后,我們得到的 dispatch 是這樣的,假設(shè) n = 3:
dispatch = f1(f2(f3(store.dispatch))));
這時調(diào)用新 dispatch,每一個 middleware 就依次執(zhí)行了。
在 middleware 中調(diào)用 dispatch 會發(fā)生什么:經(jīng)過 compose 后,所有的 middleware 算是串聯(lián)起來了??墒沁€有一個問題,在分發(fā) store 時,我們提到過每個 middleware 都可以訪問 store,即 middlewareAPI 這個變量,也可以拿到 store 的dispatch 屬性。那么,在 middleware 中調(diào)用 store.dispatch() 會發(fā)生什么,和調(diào)用 next() 有區(qū)別嗎?現(xiàn)在我們來說明兩者的不同:
const logger = store => next => action => { console.log("dispatch:", action); next(action); console.log("finish:", action); }; const logger = store => next => action => { console.log("dispatch:", action); store.dispatch(action); console.log("finish:", action); };
在分發(fā) store 時我們解釋過,middleware 中 store 的 dispatch 通過匿名函數(shù)的方式和最終compose 結(jié)束后的新 dispatch 保持一致,所以,在 middleware 中調(diào)用 store.dispatch() 和在其他任何地方調(diào)用的效果一樣。而在 middleware 中調(diào)用 next(),效果是進入下一個 middleware,下圖就是redux middleware最著名的洋蔥模型圖。
如果一個項目過大,我們通常按模塊來寫reducer,但是redux create store只接受一個reducer參數(shù),所以我們需要合并reducer。這里就用到了redux提供的combineReducer輔助函數(shù):
combineReducers({ layout, home, ...asyncReducers })
這個函數(shù)用起來很簡單,就是傳入一個對象,key是模塊reducer對應(yīng)的名字, 值是對應(yīng)reducer。值是一個function,相當(dāng)于是一個新的reducer,源碼如下:
export default function combineReducers(reducers) { var reducerKeys = Object.keys(reducers) var finalReducers = {} for (var i = 0; i < reducerKeys.length; i++) { var key = reducerKeys[i] if (process.env.NODE_ENV !== "production") { if (typeof reducers[key] === "undefined") { warning(`No reducer provided for key "${key}"`) } } if (typeof reducers[key] === "function") { finalReducers[key] = reducers[key] } } var finalReducerKeys = Object.keys(finalReducers) if (process.env.NODE_ENV !== "production") { var unexpectedKeyCache = {} } var sanityError try { assertReducerSanity(finalReducers) } catch (e) { sanityError = e } return function combination(state = {}, action) { if (sanityError) { throw sanityError } if (process.env.NODE_ENV !== "production") { var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache) if (warningMessage) { warning(warningMessage) } } 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) if (typeof nextStateForKey === "undefined") { var errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage) } nextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey !== previousStateForKey } return hasChanged ? nextState : state } }
源碼不是很多,除去一些驗證代碼,剩下的就是說:return一個function,我們暫時稱呼他combination,就相當(dāng)于是與一個總的reducer,每次action都會走到combination中,combination會遍歷輸入的reducer,將action放到每個reducer中執(zhí)行一下,計算出返回結(jié)果就是nextState,nextState于previousState如果!==說明改變了,返回nextState,否則返回執(zhí)行之前的state。
這也解釋了不同模塊actionType如果相同的話,兩個模塊的reducer都會走一遍的問題,在actionType名稱前面加上模塊前綴即可解決問題。
5. Provider與ConnectProvider與Connet組件都是React-Redux提供的核心組件,兩者看起來功能一樣,都是幫助容器組件獲取store中的數(shù)據(jù),但是原理與功能卻不同。
ProviderProvider組件在所有組件的最外層,其接受store作為參數(shù),將store里的state使用context屬性向下傳遞。部分源碼:
export default class Provider extends Component { getChildContext() { return { store: this.store } } constructor(props, context) { super(props, context) this.store = props.store } render() { const { children } = this.props return Children.only(children) } }
利用context這個屬性,Provider所有子組件均可以拿到這個屬性。
Connectconnect實現(xiàn)的功能是將需要關(guān)聯(lián)store的組件和store的dispatch等數(shù)據(jù)混合到一塊,這塊就是一個高階組件典型的應(yīng)用:
import hoistStatics from "hoist-non-react-statics" export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) { // ... return function wrapWithConnect(WrappedComponent) { // ... class Connect extends Component { // ... render() { // ... if (withRef) { this.renderedElement = createElement(WrappedComponent, { ...this.mergedProps, ref: "wrappedInstance" }) } else { this.renderedElement = createElement(WrappedComponent, this.mergedProps ) } return this.renderedElement } } // ... return hoistStatcis(Connect, WrappedComponent); } }
還是先從他的四個參數(shù)說起:
1.mapStateToPropsconnect 的第一個參數(shù)定義了我們需要從 Redux 狀態(tài)樹中提取哪些部分當(dāng)作 props 傳給當(dāng)前組件。一般來說,這也是我們使用 connect 時經(jīng)常傳入的參數(shù)。事實上,如果不傳入這個參數(shù),React 組件將永遠不會和 Redux 的狀態(tài)樹產(chǎn)生任何關(guān)系。具體在源代碼中的表現(xiàn)為:
export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) { const shouldSubscribe = Boolean(mapStateToProps) // ... class Connect extends Component { // ... trySubscribe() { if (shouldSubscribe && !this.unsubscribe) { this.unsubscribe = this.store.subscribe(this.handleChange.bind(this)) this.handleChange() } } // ... } }
mapStateToProps會訂閱 Store,每當(dāng)state更新的時候,就會自動執(zhí)行,重新計算 UI 組件的參數(shù),從而觸發(fā) UI 組件的重新渲染。
mapStateToProps的第一個參數(shù)總是state對象,還可以使用第二個參數(shù),代表容器組件的props對象。
這塊的源碼相對較簡單:
const mapState = mapStateToProps || defaultMapStateToProps class Connect extends Component { computeStateProps(store, props) { if (!this.finalMapStateToProps) { return this.configureFinalMapState(store, props) } const state = store.getState() const stateProps = this.doStatePropsDependOnOwnProps ? this.finalMapStateToProps(state, props) : this.finalMapStateToProps(state) if (process.env.NODE_ENV !== "production") { checkStateShape(stateProps, "mapStateToProps") } return stateProps } configureFinalMapState(store, props) { const mappedState = mapState(store.getState(), props) const isFactory = typeof mappedState === "function" this.finalMapStateToProps = isFactory ? mappedState : mapState this.doStatePropsDependOnOwnProps = this.finalMapStateToProps.length !== 1 if (isFactory) { return this.computeStateProps(store, props) } if (process.env.NODE_ENV !== "production") { checkStateShape(mappedState, "mapStateToProps") } return mappedState } }
這塊原理很簡單,進行一些參數(shù)校驗,判斷第一個參數(shù)mapStateToProps返回值是否為function,如果是遞歸調(diào)用,不是的話算出返回值。如果沒傳這個參數(shù),默認給{}。
我們可能會疑惑為什么傳給 connect 的第一個參數(shù)本身是一個函數(shù),react-redux 還允許這個函數(shù)的返回值也是一個函數(shù)呢?
簡單地說,這樣設(shè)計可以允許我們在 connect 的第一個參數(shù)里利用函數(shù)閉包進行一些復(fù)雜計算的緩存,從而實現(xiàn)效率優(yōu)化的目的
當(dāng)我們使用的時候:
const mapStateToProps = (state, props) => ({ home: state.home, layout: state.layout });
使用ownProps作為參數(shù)后,如果容器組件的參數(shù)發(fā)生變化,也會引發(fā) UI 組件重新渲染
2.mapDispatchToProps人如其名,它接受 store 的 dispatch 作為第一個參數(shù),同時接受 this.props 作為可選的第二個參數(shù)。利用這個方法,我們可以在 connect 中方便地將 actionCreator 與 dispatch 綁定在一起(利用 bindActionCreators 方法),最終綁定好的方法也會作為 props 傳給當(dāng)前組件。這塊的源碼與mapStateToProps一樣,就不貼了。
bindActionCreator
function bindActionCreator(actionCreator, dispatch) { return (...args) => dispatch(actionCreator(...args)) }3.mergeProps
前兩個參數(shù)返回的對象,都要跟組件自身的props merge一下,形成一個新的對象賦值給對應(yīng)組件,我們可以在這一步做一些處理,這個參數(shù)就是干這個的,該參數(shù)簽名:
mergeProps(stateProps, dispatchProps, ownProps): props
默認情況如果沒傳該參數(shù),返回Object.assign(ownProps, stateProps, dispatchProps)。
4.options如果指定這個參數(shù),可以定制 connector 的行為。
[pure = true] (Boolean): 如果為 true,connector 將執(zhí)行 shouldComponentUpdate 并且淺對比 mergeProps 的結(jié)果,避免不必要的更新,前提是當(dāng)前組件是一個“純”組件,它不依賴于任何的輸入或 state 而只依賴于 props 和 Redux store 的 state。默認值為 true。
[withRef = false] (Boolean): 如果為 true,connector 會保存一個對被包裝組件實例的引用,該引用通過 getWrappedInstance() 方法獲得。默認值為 false。
這個connect組件還干了一件事,狀態(tài)緩存判斷。當(dāng)store變了的時候,前后狀態(tài)判斷,如果狀態(tài)不等,更新組件,并且完成事件分發(fā)。
6. Redux流程梳理上面講了大量的函數(shù)源碼,這么些函數(shù)之間的關(guān)系:
初始化階段:
createStore創(chuàng)建一個store對象
將store對象通過參數(shù)給Provider組件
Provider組件將store通過context向子組件傳遞
Connect組件通過context獲取到store,存入自己的state
componentDidMount里面訂閱store.subscribe事件
更新數(shù)據(jù)階段:
用戶事件觸發(fā)
actionCreator生成action交給dispatch
實際上交給了封裝后的中間層(compose(applyMiddleware(...)))
請求依次通過每個中間件,中間件通過next進行下一步
最后一個中間件將action交給store.dispatch
dispatch內(nèi)部將action交給reducer執(zhí)行
combineReducer將每個子reducer執(zhí)行一遍算出新的state
dispatch內(nèi)部調(diào)用所有訂閱事件
Connect組件handleChange事件觸發(fā)判斷新state和舊state是否===
并且判斷新的state是否與mapStateToProps shallowEqual
不等則setState觸發(fā)更新
7.Redux設(shè)計技巧匿名函數(shù)&&閉包使用
redux核心函數(shù)大量使用了匿名函數(shù)和閉包來實現(xiàn)數(shù)據(jù)共享和狀態(tài)同步。
函數(shù)柯里化使用
使用函數(shù)柯里化s實現(xiàn)參數(shù)復(fù)用,本質(zhì)上是降低通用性,提高適用性。
核心狀態(tài)讀取是拷貝而不是地址
對于state這種核心狀態(tài)使用getState()計算出新的state,而不是直接返回一個state對象。
觀察者訂閱者是核心實現(xiàn)
使用觀察者訂閱者模式實現(xiàn)數(shù)據(jù)響應(yīng)。
context這個api的使用
平時開發(fā)不常接觸的api實現(xiàn)Provider與Connect通信。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93471.html
摘要:歡迎關(guān)注源碼分析系列文章源碼分析之一源碼分析之二源碼分析之三源碼分析之四源碼分析之五文件算是非常簡單的一個文件了,該文件就實現(xiàn)一個目的以前這樣觸發(fā)一個,即,現(xiàn)在變成這樣觸發(fā)一個。目的很單純,簡化某個的調(diào)用。 歡迎關(guān)注redux源碼分析系列文章:redux源碼分析之一:createStore.jsredux源碼分析之二:combineReducers.jsredux源碼分析之三:bind...
摘要:歡迎關(guān)注源碼分析系列文章源碼分析之一源碼分析之二源碼分析之三源碼分析之四源碼分析之五文件對外暴露了一個函數(shù),函數(shù)是的一個輔助性的函數(shù),用于拆分里面的第一個參數(shù)函數(shù)。函數(shù)的返回值是一個函數(shù),該函數(shù)是組合之后的一個標準的函數(shù)。 歡迎關(guān)注redux源碼分析系列文章:redux源碼分析之一:createStore.jsredux源碼分析之二:combineReducers.jsredux源碼分...
摘要:的中間件主要是通過模塊實現(xiàn)的。返回的也是一個對象這個其實就是,各個中間件的最底層第三層的哪個函數(shù)組成的圓環(huán)函數(shù)構(gòu)成的這就是對源碼的一個整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測試例子可以關(guān)注源碼解讀倉庫 applyMiddleware源碼解析 中間件機制在redux中是強大且便捷的,利用redux的中間件我們能夠?qū)崿F(xiàn)日志記錄,異步調(diào)用等多種十分實用的功能。redux的中間件主要是...
摘要:實現(xiàn)一個先不考慮中間件,實現(xiàn)一個簡潔的實現(xiàn)是最主要的一個了,通過可以創(chuàng)建一個用來存放應(yīng)用中所有的,一個應(yīng)用只能有一個。方法是用來把每一個用方法包裹一下,因為可能只是返回一個具有屬性的對象,只有用執(zhí)行才有意義。正好可以利用的特性實現(xiàn)這個效果。 實現(xiàn)一個redux 先不考慮中間件,實現(xiàn)一個簡潔的redux 實現(xiàn)createStore createStore是redux最主要的一個API了,...
摘要:的返回值是函數(shù),這個函數(shù)經(jīng)調(diào)用,傳入?yún)?shù),之后會在中間件鏈上進行傳遞,只要保證每個中間件的參數(shù)是并且將傳遞給下一個中間件。 了解了Redux原理之后,我很好奇Redux中間件是怎么運作的,于是選了最常用的redux-thunk進行源碼分析。 此次分析用的redux-thunk源碼版本是2.2.0,redux源碼版本是3.7.2。并且需要了解Redux原理 redux中間件都是由redu...
閱讀 1014·2019-08-30 15:55
閱讀 3456·2019-08-30 13:10
閱讀 1282·2019-08-29 18:45
閱讀 2363·2019-08-29 16:25
閱讀 2123·2019-08-29 15:13
閱讀 2435·2019-08-29 11:29
閱讀 566·2019-08-26 17:34
閱讀 1503·2019-08-26 13:57