摘要:上篇文章庖丁解牛一介紹了的幾個(gè)重要的原理,其中是函數(shù)的基礎(chǔ),這篇文章將主要介紹函數(shù)的原理。這意味著任何時(shí)刻更新,將會(huì)被調(diào)用。隨后便是函數(shù)的重點(diǎn)部分,根據(jù)是否為選擇恰當(dāng)?shù)模缓蠓祷亍W罱K執(zhí)行函數(shù),緩存結(jié)果并傳入被包裹的組件。
connect API
上篇文章庖丁解牛React-Redux(一): connectAdvanced介紹了react-redux的Provider、connectAdvanced幾個(gè)重要API的原理,其中connectAdvanced是connect函數(shù)的基礎(chǔ),這篇文章將主要介紹connect函數(shù)的原理。之前沒有閱讀過connectAdvanced最好提前閱讀一下這篇文章。之前的文章有讀者反映看起來比較晦澀,所以我準(zhǔn)備隨后會(huì)出一篇關(guān)于類似圖解connectAdvanced的文章,不講代碼,主要從原理的方面詮釋connectAdvanced。再次做個(gè)廣告,歡迎大家關(guān)注我的掘金賬號(hào)和我的博客。
最開始我們還是來介紹一下connect函數(shù):
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
將React組件連接到Redux store,connect函數(shù)是connectAdvanced的正面,為大多數(shù)常見場(chǎng)景提供了易于使用的API。connect函數(shù)并不會(huì)修改傳遞的組件,相反,它會(huì)返回一個(gè)新的,連接到store的組件類。
參數(shù):
[mapStateToProps(state, [ownProps]): stateProps](Function):
如果這個(gè)參數(shù)被傳遞,返回新的組件將會(huì)訂閱Redux的store的更新(update)。這意味著任何時(shí)刻store更新,mapStateToProps將會(huì)被調(diào)用。mapStateToProps必須返回一個(gè)純對(duì)象(plain object),這個(gè)對(duì)象將會(huì)合并進(jìn)組件的屬性(props)。如果你不想訂閱store的更新,可以給mapStateToProps參數(shù)傳遞null或者undefined。
如果你的mapStateToProps函數(shù)被聲明接受兩個(gè)參數(shù),mapStateToProps在調(diào)用時(shí)第一個(gè)參數(shù)是store state,傳遞給連接組件(connected component)的屬性將會(huì)被作為第二個(gè)參數(shù)。如果連接組件接受到新的props(淺比較),mapStateToProps也會(huì)再次調(diào)用。
注意: 在一些更高級(jí)的情況下,你需要更好的控制渲染的性能,mapStateToProps可以返回一個(gè)函數(shù)。這種場(chǎng)景下,返回的函數(shù)將會(huì)被作為特定組件實(shí)例的mapStateProps()函數(shù)。這允許你可以對(duì)每個(gè)實(shí)例緩存。但大部分應(yīng)用用不到。
mapStateToProps函數(shù)接受一個(gè)參數(shù): Redux中store的state,并返回一個(gè)對(duì)象作為屬性返回給被包裹的組件。這通常被稱為`selector。
mapDispatchToProps(dispatch, [ownProps]): dispatchProps:
如果傳入?yún)?shù)是一個(gè)對(duì)象,對(duì)象中的每個(gè)函數(shù)都被認(rèn)為是Redux的action creator函數(shù)。返回的對(duì)象中的每個(gè)action creator函數(shù)都會(huì)被dispatch所包裹,因此可以直接調(diào)用,最終會(huì)被合并進(jìn)入組件的屬性。
如果傳遞一個(gè)函數(shù),該函數(shù)的第一個(gè)參數(shù)為dispatch。需要你返回一個(gè)對(duì)象,其中的屬性以你的方式將dispatch與action creator相綁定。
如果你的mapDispatchToProps函數(shù)聲明接受兩個(gè)參數(shù),第一個(gè)函數(shù)是dispatch,第二個(gè)參數(shù)是傳遞給連接組件的屬性。每當(dāng)連接組件收到新的參數(shù)時(shí),mapDispatchToProps就會(huì)被再次調(diào)用。
如果沒有傳入自定義的mapDispatchToProps函數(shù)或者對(duì)象,默認(rèn)的mapDispatchToProps將為你的組件注入dispatch屬性。
注意: mapDispatchToProps也可以返回函數(shù),用法與mapStateToProps相同
mergeProps(stateProps, dispatchProps, ownProps): props:
如果指定了這個(gè)參數(shù),傳入的參數(shù)為:函數(shù) mapStateToProps()、mapDispatchToProps()的運(yùn)行結(jié)果以及傳入連接組件的屬性。從該函數(shù)返回的對(duì)象將會(huì)被當(dāng)做屬性傳遞給被包裹的組件。你可能會(huì)指定這個(gè)函數(shù)來基于props來選擇性傳入state,或者按照傳入props綁定action creator。如果你省略了這個(gè)函數(shù),默認(rèn)是實(shí)現(xiàn)方式是:`
Object.assign({}, ownProps, stateProps, dispatchProps)
`
options
如果你指定了這個(gè)選項(xiàng),更進(jìn)一步自定義connector的行為。除了可以傳入connectAdvanced的選項(xiàng),還可以接受額外的選項(xiàng):
[pure] (Boolean): 如果參數(shù)為true,用來避免重新渲染并調(diào)用mapStateToProps、mapDispatchToProps和mergeProps時(shí)基于各自的等值比較函數(shù)來比較所涉及到的state和props對(duì)象。
[areStatesEqual] (Function): 如果參數(shù)pure為true,用來比較傳入的store與之前的store值。默認(rèn)值: strictEqual (===)。
[areOwnPropsEqual] (Function):如果參數(shù)pure為true,用來比較傳入的props與之前的props值。默認(rèn)值: strictEqual (===)。
[areStatePropsEqual] (Function):如果參數(shù)pure為true,用以比較mapStateToProps函數(shù)的結(jié)果與之前的結(jié)果值。
[areMergedPropsEqual] (Function): 如果參數(shù)pure為true,比較mergeProps函數(shù)的結(jié)果與之前的值。默認(rèn)值為:shallowEqual。
[storeKey] (String): 用以從context獲取store的key值。你僅僅可能在有多個(gè)store值的情況下才需要這個(gè)選項(xiàng),默認(rèn)值為:store。
connect源碼connect的代碼如下:
export function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories = defaultMapStateToPropsFactories, mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories, mergePropsFactories = defaultMergePropsFactories, selectorFactory = defaultSelectorFactory } = {}) { return function connect( mapStateToProps, mapDispatchToProps, mergeProps, { pure = true, areStatesEqual = strictEqual, areOwnPropsEqual = shallowEqual, areStatePropsEqual = shallowEqual, areMergedPropsEqual = shallowEqual, ...extraOptions } = {} ) { const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, "mapStateToProps") const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, "mapDispatchToProps") const initMergeProps = match(mergeProps, mergePropsFactories, "mergeProps") return connectHOC(selectorFactory, { methodName: "connect", getDisplayName: name => `Connect(${name})`, shouldHandleStateChanges: Boolean(mapStateToProps), initMapStateToProps, initMapDispatchToProps, initMergeProps, pure, areStatesEqual, areOwnPropsEqual, areStatePropsEqual, areMergedPropsEqual, ...extraOptions }) } } const connect = createConnect();
createConnect作為高階函數(shù),返回connect函數(shù),通過柯里化的方式首先接受以下參數(shù): connectHOC、mapStateToPropsFactories、mapDispatchToPropsFactories、mergePropsFactories與selectorFactory。
傳入用來生成連接到store的高階組件(HOC),默認(rèn)是之前介紹過的connectAdvanced。
selectorFactory用來生成selector,第一個(gè)參數(shù)將傳入connectAdvanced。我們知道傳入connectAdvanced的selectorFactory函數(shù)主要是初始化selector函數(shù)。selector函數(shù)在每次connector component需要計(jì)算新的props都會(huì)被調(diào)用,selector函數(shù)會(huì)返回純對(duì)象(plain object),這個(gè)對(duì)象會(huì)作為props傳遞給被包裹的組件(WrappedComponent)。selectorFactory的函數(shù)簽名為:
selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props (Function)
我們來看看redux的selectorFactory是怎么定義的:
const selectorFactory = finalPropsSelectorFactory(dispatch, { initMapStateToProps, initMapDispatchToProps, initMergeProps, ...options }) { const mapStateToProps = initMapStateToProps(dispatch, options) const mapDispatchToProps = initMapDispatchToProps(dispatch, options) const mergeProps = initMergeProps(dispatch, options) if (process.env.NODE_ENV !== "production") { verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps, options.displayName) } const selectorFactory = options.pure ? pureFinalPropsSelectorFactory : impureFinalPropsSelectorFactory return selectorFactory( mapStateToProps, mapDispatchToProps, mergeProps, dispatch, options ) }
selectorFactory函數(shù)首先接受兩個(gè)參數(shù),dispatch和一系列的factoryOptions,通過一系列的初始化函數(shù)分別生成了mapStateToProps、mapDispatchToProps、mergeProps(初始化函數(shù)隨后會(huì)詳細(xì)介紹)。然后會(huì)在非生產(chǎn)環(huán)境下對(duì)上述三個(gè)函數(shù)進(jìn)行驗(yàn)證(驗(yàn)證主要涉及到該函數(shù)是否為空和函數(shù)中是否有dependsOnOwnProps屬性,這個(gè)屬性隨后會(huì)介紹的)。隨后便是函數(shù)的重點(diǎn)部分,根據(jù)options.pure是否為true,選擇恰當(dāng)?shù)?b>selectorFactory,然后返回selectorFactory(...args)。
當(dāng)options.pure為false時(shí),selectorFactory的值為:impureFinalPropsSelectorFactory:
function impureFinalPropsSelectorFactory( mapStateToProps, mapDispatchToProps, mergeProps, dispatch ) { return function impureFinalPropsSelector(state, ownProps) { return mergeProps( mapStateToProps(state, ownProps), mapDispatchToProps(dispatch, ownProps), ownProps ) } }
我們知道,selectorFactory會(huì)返回selector函數(shù),返回的函數(shù)會(huì)接受兩個(gè)參數(shù):state與ownProps并最終返回屬性傳遞給被包裹的組件。我們發(fā)現(xiàn)impureFinalPropsSelectorFactory非常的簡(jiǎn)單,只是單純的將要求的參數(shù)傳遞給mapStateToProps,mapDispatchToProps,并將其結(jié)果連同ownProps一起傳遞給mergeProps,并將最后mergeProps的結(jié)果作為selector函數(shù)的結(jié)果。這個(gè)結(jié)果最終會(huì)傳遞給被包裹組件,這個(gè)函數(shù)沒有什么難度而且非常符合connect函數(shù)的API。
但我們知道在默認(rèn)情況下,options.pure為true。因此selectorFactory的值為:pureFinalPropsSelectorFactory:
pureFinalPropsSelectorFactory( mapStateToProps, mapDispatchToProps, mergeProps, dispatch, { areStatesEqual, areOwnPropsEqual, areStatePropsEqual } ) { let hasRunAtLeastOnce = false let state let ownProps let stateProps let dispatchProps let mergedProps // ...... return function pureFinalPropsSelector(nextState, nextOwnProps) { return hasRunAtLeastOnce ? handleSubsequentCalls(nextState, nextOwnProps) : handleFirstCall(nextState, nextOwnProps) } }
函數(shù)pureFinalPropsSelectorFactory中有一個(gè)閉包變量hasRunAtLeastOnce用來判斷是否是第一次調(diào)用,如果selector函數(shù)是第一次調(diào)用,selector會(huì)返回handleFirstCall(nextState, nextOwnProps)否則返回handleSubsequentCalls(nextState, nextOwnProps)。
function handleFirstCall(firstState, firstOwnProps) { state = firstState ownProps = firstOwnProps stateProps = mapStateToProps(state, ownProps) dispatchProps = mapDispatchToProps(dispatch, ownProps) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) hasRunAtLeastOnce = true return mergedProps }
handleFirstCall與之前的impureFinalPropsSelector相比,只是做了緩存,保存了state、ownProps以及mapStateToProps、dispatchProps和mergedProps的結(jié)果值。
function handleSubsequentCalls(nextState, nextOwnProps) { const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps) const stateChanged = !areStatesEqual(nextState, state) state = nextState ownProps = nextOwnProps if (propsChanged && stateChanged) return handleNewPropsAndNewState() if (propsChanged) return handleNewProps() if (stateChanged) return handleNewState() return mergedProps }
再看函數(shù)handleSubsequentCalls。其中areOwnPropsEqual、areStatesEqual分別用來判斷props和state現(xiàn)在的值與緩存的值是否相等函數(shù)。handleSubsequentCalls首先判斷state、props的前后值是否有變化,然后緩存了state、ownProps。如果props和state都發(fā)送改變了,返回handleNewPropsAndNewState的結(jié)果,如果props改變了,返回handleNewProps的運(yùn)行結(jié)果。如果state改變,返回handleNewState運(yùn)行結(jié)果,否則如果state和props都沒發(fā)生改變,說明都沒有發(fā)生改變。直接返回之前緩存的mergedProps的值。
handleNewPropsAndNewState定義如下:
function handleNewPropsAndNewState() { stateProps = mapStateToProps(state, ownProps) if (mapDispatchToProps.dependsOnOwnProps) dispatchProps = mapDispatchToProps(dispatch, ownProps) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
我們看到,如果props和state都發(fā)送改變了,調(diào)用了handleNewPropsAndNewState,首先就是運(yùn)行
mapStateToProps返回stateProps的值并緩存,其次我們會(huì)根據(jù)mapDispatchToProps.dependsOnOwnProps的值去判別是否運(yùn)行mapDispatchToProps。dependsOnOwnProps的值主要是用來判別mapDispatchToProps是否依賴于ownProps的值。最終執(zhí)行mergeProps函數(shù),緩存結(jié)果并傳入被包裹的組件。
function handleNewProps() { if (mapStateToProps.dependsOnOwnProps) stateProps = mapStateToProps(state, ownProps) if (mapDispatchToProps.dependsOnOwnProps) dispatchProps = mapDispatchToProps(dispatch, ownProps) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
理解了handleNewPropsAndNewState,handleNewProps將會(huì)非常簡(jiǎn)單,分別去判別state與dispatchProps是否與ownProps相關(guān)。以判別是否需要重新運(yùn)行mapStateToProps和mapDispatchToProps。最終將mergeProps運(yùn)行的值緩存并傳遞給被包裹的組件。
function handleNewState() { const nextStateProps = mapStateToProps(state, ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
handleNewState用來生成新的state。根據(jù)是否state變化,選擇性是否執(zhí)行mergeProps,最終返回mergedProps給被包裹組件。
到現(xiàn)在為止,其實(shí)我們已經(jīng)知道了selectorFactory是與pure值掛鉤的。如果pure為true的話,selectorFactory返回的selector會(huì)對(duì)state和props等值都會(huì)緩存,然后會(huì)根據(jù)具體的場(chǎng)景,盡可能使得傳入被包裹組件的值改動(dòng)最少(即盡可能返回相同的值),其目的就是減少不必要的渲染。當(dāng)pure為false值,不會(huì)做任何的緩存。
看完了selectorFactory,我們需要去了解一下mapStateToProps是怎么來的:
//connect.js // initMapStateToProps會(huì)被傳入 selectorFactory const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, "mapStateToProps")
//selectorFactory.js const mapStateToProps = initMapStateToProps(dispatch, options) //mapStateToProps的使用(注意這里的mapStateToProps不是傳入的函數(shù),而是init函數(shù)生成的函數(shù)): const stateProps = mapStateToProps(state, ownProps)
我們可以看到,首先在connect.js中通過match函數(shù)取生成initMapStateToProps。然后在selectorFactory中,生成了mapStateToProps的函數(shù),然后會(huì)在selector函數(shù)中使用mapStateToProps生成了stateProps,最后將stateProps傳遞給被包裹的組件。
首先看match函數(shù)的定義:
function match(arg, factories, name) { for (let i = factories.length - 1; i >= 0; i--) { const result = factories[i](arg) if (result) return result } return (dispatch, options) => { throw new Error(`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${options.wrappedComponentName}.`) } }
接下來的內(nèi)容相對(duì)來說會(huì)比較復(fù)雜,我們先提前梳理一下match函數(shù)的運(yùn)作,其中factories是一個(gè)數(shù)組,它的實(shí)參將會(huì)是類似于mapStateToPropsFactories(數(shù)組)等值,然后args將是你自定義的mapStateToProps函數(shù)等值(比如mapStateToDispatch)。我們將會(huì)以args作為參數(shù)從后到前執(zhí)行factories數(shù)組中的每一個(gè)函數(shù),找到第一個(gè)返回不為假(類似于undefined)的函數(shù)并且我們可以保證這個(gè)函數(shù)返回的是另一個(gè)函數(shù),其簽名類似于:
(dispatch,options)=>{ //.... return ()=>{ } }
這個(gè)返回的函數(shù)接受dispatch和其他選項(xiàng)options作為參數(shù),最終返回一個(gè)函數(shù)供selector使用的函數(shù) ,比如mapStateToPropsFactories一定會(huì)返回一個(gè)類似與于下面的函數(shù):
(state, ownProps) =>{ //...... //return plain object }
這個(gè)函數(shù)將用來計(jì)算新的state傳遞給被包裹的組件。
對(duì)于mapStateToProps的來源要追溯到:
const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, "mapStateToProps")
在函數(shù)match中第一個(gè)實(shí)參是你傳入connect的mapStateToProps。第二個(gè)實(shí)參mapStateToPropsFactories的定義如下:
const mapStateToPropsFactories = [ whenMapStateToPropsIsFunction, whenMapStateToPropsIsMissing ]; function whenMapStateToPropsIsFunction(mapStateToProps) { return (typeof mapStateToProps === "function") ? wrapMapToPropsFunc(mapStateToProps, "mapStateToProps") : undefined } function whenMapStateToPropsIsMissing(mapStateToProps) { return (!mapStateToProps) ? wrapMapToPropsConstant(() => ({})) : undefined }
上面的代碼都不難,首先判斷傳入的mapStateToProps是不是類似于null,如果是執(zhí)行whenMapStateToPropsIsMissing否則去執(zhí)行whenMapStateToPropsIsFunction。對(duì)于whenMapStateToPropsIsMissing來說,重要的是whenMapStateToPropsIsMissing的定義:
function wrapMapToPropsConstant(getConstant) { return function initConstantSelector(dispatch, options) { const constant = getConstant(dispatch, options) function constantSelector() { return constant } constantSelector.dependsOnOwnProps = false return constantSelector } }
wrapMapToPropsConstant函數(shù)接受的參數(shù)是一個(gè)函數(shù),這個(gè)函數(shù)負(fù)責(zé)在selector返回一個(gè)常量作為props返回給被包裹組件。因?yàn)榉祷氐目偸且粋€(gè)常量,所以dependsOnOwnProps為false,表示返回給被包裹組件的值與連接到store的高階組件接受到的props無關(guān)。
那么whenMapStateToPropsIsMissing函數(shù)調(diào)用wrapMapToPropsConstant的參數(shù)是一個(gè)空函數(shù)(()=>{}),那就說明在mapStateToProps值為空(null)的時(shí)候,是不給被包裹組件傳遞任何的屬性的。
whenMapStateToPropsIsFunction的情況會(huì)比較復(fù)雜,如果傳入的mapStateToProps是一個(gè)函數(shù),那么就會(huì)調(diào)用wrapMapToPropsFunc:
function wrapMapToPropsFunc(mapToProps, methodName) { return function initProxySelector(dispatch, { displayName }) { const proxy = function mapToPropsProxy(stateOrDispatch, ownProps) { return proxy.dependsOnOwnProps ? proxy.mapToProps(stateOrDispatch, ownProps) : proxy.mapToProps(stateOrDispatch) } proxy.dependsOnOwnProps = true proxy.mapToProps = function detectFactoryAndVerify(stateOrDispatch, ownProps) { proxy.mapToProps = mapToProps proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps) let props = proxy(stateOrDispatch, ownProps) if (typeof props === "function") { proxy.mapToProps = props proxy.dependsOnOwnProps = getDependsOnOwnProps(props) props = proxy(stateOrDispatch, ownProps) } if (process.env.NODE_ENV !== "production") verifyPlainObject(props, displayName, methodName) return props } return proxy } }
wrapMapToPropsFunc的函數(shù)相對(duì)來說比較復(fù)雜,接受的參數(shù)是你傳入的mapStateToProps函數(shù)(methodName的作用只是錯(cuò)誤提示),返回的是初始化selector函數(shù)(initProxySelector)。當(dāng)使用initProxySelector初始化selector的時(shí)候,返回的函數(shù)proxy實(shí)則為一個(gè)代理(proxy)。第一次執(zhí)行proxy(selector)時(shí),dependsOnOwnProps的值為true,所以相當(dāng)于執(zhí)行proxy.mapToProps(stateOrDispatch, ownProps)(detectFactoryAndVerify),然后將proxy.mapToProps屬性設(shè)置為你所傳入的mapStateToProps函數(shù)。這時(shí)候再去執(zhí)行getDependsOnOwnProps的目的是去確定你傳入的mapStateToProps是否需要傳入props。然后再去執(zhí)行proxy(stateOrDispatch, ownProps),這時(shí)候proxy.mapToProps已經(jīng)不是之前的detectFactoryAndVerify而是你傳入的mapStateToProps(所以不會(huì)出現(xiàn)死循環(huán))。執(zhí)行的結(jié)果就是mapStateToProps運(yùn)行后的結(jié)果。如果prop是對(duì)象,將會(huì)直接傳遞給被包裹組件。但是我們之前講過,mapStateToProps是可以返回一個(gè)函數(shù)的,如果返回的值為一個(gè)函數(shù),這個(gè)函數(shù)將會(huì)被作為proxy的mapStateToProps,再次去執(zhí)行proxy。
再去了解一下mapStateToProps的來源:
//connect.js const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, "mapDispatchToProps")
//selectFactory const mapDispatchToProps = initMapDispatchToProps(dispatch, options) //使用: const dispatchProps = mapDispatchToProps(dispatch, ownProps)
其實(shí)mapDispatchToProps是和mapStateToProps的來源非常相似,照理看mapDispatchToPropsFactories:
const mapDispatchToPropsFactories = [ whenMapDispatchToPropsIsFunction, whenMapDispatchToPropsIsMissing, whenMapDispatchToPropsIsObject ] function whenMapDispatchToPropsIsFunction(mapDispatchToProps) { return (typeof mapDispatchToProps === "function") ? wrapMapToPropsFunc(mapDispatchToProps, "mapDispatchToProps") : undefined } function whenMapDispatchToPropsIsMissing(mapDispatchToProps) { return (!mapDispatchToProps) ? wrapMapToPropsConstant(dispatch => ({ dispatch })) : undefined } function whenMapDispatchToPropsIsObject(mapDispatchToProps) { return (mapDispatchToProps && typeof mapDispatchToProps === "object") ? wrapMapToPropsConstant(dispatch => bindActionCreators(mapDispatchToProps, dispatch)) : undefined }
如果你已經(jīng)看懂了wrapMapToPropsConstant和wrapMapToPropsFunc的函數(shù)的話,mapDispatchToPropsFactories也就不難了。如果傳入的mapStateToProps的值是一個(gè)對(duì)象的話,會(huì)調(diào)用whenMapDispatchToPropsIsObject。繼而調(diào)用了wrapMapToPropsConstant并傳入的參數(shù)是函數(shù):dispatch => bindActionCreators(mapDispatchToProps, dispatch)。根據(jù)我們之前經(jīng)驗(yàn),那么傳遞給被包裹的組件的屬性將是:bindActionCreators(mapDispatchToProps, dispatch)的運(yùn)行結(jié)果,即被dispatch包裹的action。
如果沒有傳入mapDispatchToProps函數(shù)的話,調(diào)用whenMapDispatchToPropsIsMissing。傳入函數(shù)wrapMapToPropsConstant的參數(shù)為:dispatch => ({ dispatch }),那么被包裹的組件接受的參數(shù)即是store的dispatch方法。
如果傳入的mapDispatchToProps是一個(gè)函數(shù),調(diào)用whenMapDispatchToPropsIsFunction函數(shù)。從而調(diào)用wrapMapToPropsFunc(mapDispatchToProps, "mapDispatchToProps")。運(yùn)行的原理與運(yùn)行wrapMapToPropsFunc(mapStateToProps, "mapStateToProps")基本相同,可以參照之前。
//connect.js const initMergeProps = match(mergeProps, mergePropsFactories, "mergeProps")
//selectorFactory const mergeProps = initMergeProps(dispatch, options) //使用 mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
還是先看一下mergePropsFactories是怎么定義的:
const mergePropsFactories = [ whenMergePropsIsFunction, whenMergePropsIsOmitted ] function whenMergePropsIsFunction(mergeProps) { return (typeof mergeProps === "function") ? wrapMergePropsFunc(mergeProps) : undefined } function whenMergePropsIsOmitted(mergeProps) { return (!mergeProps) ? () => defaultMergeProps : undefined }
如果你沒有傳入mapStateToProps函數(shù),那么調(diào)用函數(shù)whenMergePropsIsOmitted()。到最后margedProps函數(shù)即是defaultMergeProps,defaultMergeProps的定義為:
function defaultMergeProps(stateProps, dispatchProps, ownProps) { return { ...ownProps, ...stateProps, ...dispatchProps } }
如果你傳入了mapStateToProps函數(shù),調(diào)用函數(shù)whenMergePropsIsFunction(),調(diào)用了wrapMergePropsFunc(mergeProps),其中參數(shù)mergeProps即是你所傳入的mergeProps:
function wrapMergePropsFunc(mergeProps) { return function initMergePropsProxy(dispatch, { displayName, pure, areMergedPropsEqual }) { let hasRunOnce = false let mergedProps return function mergePropsProxy(stateProps, dispatchProps, ownProps) { const nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps) if (hasRunOnce) { if (!pure || !areMergedPropsEqual(nextMergedProps, mergedProps)) mergedProps = nextMergedProps } else { hasRunOnce = true mergedProps = nextMergedProps if (process.env.NODE_ENV !== "production") verifyPlainObject(mergedProps, displayName, "mergeProps") } return mergedProps } } }
wrapMergePropsFunc中涉及到性能優(yōu)化,首先wrapMergePropsFunc返回一個(gè)初始mergeProps的函數(shù)(mergePropsProxy)。函數(shù)mergePropsProxy閉包一個(gè)變量hasRunOnce來記錄mergeProps運(yùn)行次數(shù),在mergeProps第一次運(yùn)行時(shí),會(huì)保存第一次傳入被包裹組件的的props,再以后的運(yùn)行過程中,如果你傳入的參數(shù)pure為true并且前后的mergedProps值不同時(shí)(比較函數(shù)你可以自定義)才會(huì)傳入新的屬性,否則將傳入之前的緩存值,以此來優(yōu)化不必要的渲染。
到此為止,我們基本已經(jīng)在代碼層面講完了connect函數(shù)的原理,文章很長(zhǎng),有的地方可能相對(duì)比較難理解,建議大家都可以去從整體上看看react-redux的源碼。react-redux源碼解讀系列接下來會(huì)以其他的角度去分析react-redux,歡迎大家繼續(xù)關(guān)注。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/84307.html
摘要:前端日?qǐng)?bào)精選庖丁解牛二深入解析模板字符串八段代碼徹底掌握高效壓縮文件束的體積譯才不是什么黑魔法呢發(fā)布中文譯數(shù)據(jù)結(jié)構(gòu)棧與隊(duì)列瘋狂的技術(shù)宅中自定義指令修仙之路更好的異步解決方案發(fā)布同步代碼書寫異步情懷有贊前端團(tuán)隊(duì)位運(yùn)算,也許 2017-07-26 前端日?qǐng)?bào) 精選 庖丁解牛React-Redux(二): connect深入解析 ES6:模板字符串_ES6八段代碼徹底掌握Promise高效壓縮...
摘要:前端日?qǐng)?bào)精選入門指南入口,輸出,加載器和插件中數(shù)據(jù)類型轉(zhuǎn)換讓我印象深刻的面試題大話大前端時(shí)代一與的組件化庖丁解牛一發(fā)布中文第期手把手教你用管理狀態(tài)上個(gè)快速編程技巧眾成翻譯中執(zhí)行順序組件解耦之道眾成翻譯組件模型啟示錄有個(gè)梨作 2017-07-10 前端日?qǐng)?bào) 精選 Webpack入門指南: 入口,輸出,加載器和插件JavaScript中數(shù)據(jù)類型轉(zhuǎn)換讓我印象深刻的javascript面試題大...
摘要:和的結(jié)合簡(jiǎn)述相信很多前端開發(fā)者都聽說或使用過,我曾寫過一篇關(guān)于快速理解的文章,雖說是快速理解,但實(shí)際上更應(yīng)該叫做復(fù)習(xí)吧。它通過高階函數(shù),純函數(shù)使我們?cè)诰帉懡M件時(shí)完全不用接觸相關(guān)內(nèi)容,只通過將組件和數(shù)據(jù)連接起來即可。 react-redux react和redux的結(jié)合 簡(jiǎn)述 相信很多前端開發(fā)者都聽說或使用過react-redux,我曾寫過一篇關(guān)于快速理解redux的文章,雖說是快...
摘要:手挽手帶你學(xué)入門四檔用人話教你,理解架構(gòu),以及運(yùn)用在中。學(xué)完這一章,你就可以開始自己的項(xiàng)目了。結(jié)合搭建基礎(chǔ)環(huán)境我們上一章講過了的原理,內(nèi)部是有一個(gè)的,只有才可以控制它變化。 手挽手帶你學(xué)React入門四檔,用人話教你react-redux,理解redux架構(gòu),以及運(yùn)用在react中。學(xué)完這一章,你就可以開始自己的react項(xiàng)目了。 視頻教程 上一篇我們自己實(shí)現(xiàn)了Redux,這一篇我們來...
摘要:一組件將所有組件分成兩大類組件和容器組件。前者負(fù)責(zé)與外部的通信,將數(shù)據(jù)傳給后者,由后者渲染出視圖。也就是說,用戶負(fù)責(zé)視覺層,狀態(tài)管理則是全部交給它。前者需要從計(jì)算得到,后者需要向外發(fā)出。最后,生成對(duì)象,并使用在根組件外面包一層。 一、UI 組件 React-Redux 將所有組件分成兩大類:UI 組件(presentational component)和容器組件(container c...
閱讀 1443·2021-11-22 13:54
閱讀 4323·2021-09-22 15:56
閱讀 1815·2021-09-03 10:30
閱讀 1318·2021-09-03 10:30
閱讀 2086·2019-08-30 15:55
閱讀 1851·2019-08-30 14:13
閱讀 2059·2019-08-29 15:19
閱讀 2341·2019-08-28 18:13