connect API
上篇文章庖丁解牛React-Redux(一): connectAdvanced介紹了react-redux的Provider
、connectAdvanced
幾個重要API的原理,其中connectAdvanced
是connect
函式的基礎,這篇文章將主要介紹connect
函式的原理。之前沒有閱讀過connectAdvanced
最好提前閱讀一下這篇文章。之前的文章有讀者反映看起來比較晦澀,所以我準備隨後會出一篇關於類似圖解connectAdvanced
的文章,不講程式碼,主要從原理的方面詮釋connectAdvanced
。再次做個廣告,歡迎大家關注我的掘金賬號和我的部落格。
最開始我們還是來介紹一下connect
函式:
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])複製程式碼
將React元件連線到Redux store,connect
函式是connectAdvanced
的正面,為大多數常見場景提供了易於使用的API。connect
函式並不會修改傳遞的元件,相反,它會返回一個新的,連線到store
的元件類。
引數:
-
mapStateToProps(state, [ownProps]): stateProps:
如果這個引數被傳遞,返回新的元件將會訂閱Redux的store的更新(update)。這意味著任何時刻store
更新,mapStateToProps
將會被呼叫。mapStateToProps
必須返回一個純物件(plain object),這個物件將會合並進元件的屬性(props)。如果你不想訂閱store的更新,可以給mapStateToProps
引數傳遞null
或者undefined
。如果你的
mapStateToProps
函式被宣告接受兩個引數,mapStateToProps
在呼叫時第一個引數是store state
,傳遞給連線元件(connected component)的屬性將會被作為第二個引數。如果連線元件接受到新的props(淺比較),mapStateToProps
也會再次呼叫。
注意: 在一些更高階的情況下,你需要更好的控制渲染的效能,
mapStateToProps
可以返回一個函式。這種場景下,返回的函式將會被作為特定元件例項的mapStateProps()
函式。這允許你可以對每個例項快取。但大部分應用用不到。
mapStateToProps
函式接受一個引數: Redux中store的state,並返回一個物件作為屬性返回給被包裹的元件。這通常被稱為`selector。
-
mapDispatchToProps(dispatch, [ownProps]): dispatchProps:
如果傳入引數是一個物件,物件中的每個函式都被認為是Redux的action creator函式。返回的物件中的每個action creator函式都會被
dispatch
所包裹,因此可以直接呼叫,最終會被合併進入元件的屬性。如果傳遞一個函式,該函式的第一個引數為
dispatch
。需要你返回一個物件,其中的屬性以你的方式將dispatch
與action creator相繫結。如果你的
mapDispatchToProps
函式宣告接受兩個引數,第一個函式是dispatch
,第二個引數是傳遞給連線元件的屬性。每當連線元件收到新的引數時,mapDispatchToProps
就會被再次呼叫。如果沒有傳入自定義的
mapDispatchToProps
函式或者物件,預設的mapDispatchToProps
將為你的元件注入dispatch
屬性。
注意:
mapDispatchToProps
也可以返回函式,用法與mapStateToProps
相同
-
mergeProps(stateProps, dispatchProps, ownProps): props:
如果指定了這個引數,傳入的引數為:函式
mapStateToProps()
、mapDispatchToProps()
的執行結果以及傳入連線元件的屬性。從該函式返回的物件將會被當做屬性傳遞給被包裹的元件。你可能會指定這個函式來基於props來選擇性傳入state,或者按照傳入props繫結action creator。如果你省略了這個函式,預設是實現方式是:Object.assign({}, ownProps, stateProps, dispatchProps)
-
options
如果你指定了這個選項,更進一步自定義connector的行為。除了可以傳入connectAdvanced
的選項,還可以接受額外的選項:- [pure] (Boolean): 如果引數為true,用來避免重新渲染並呼叫
mapStateToProps
、mapDispatchToProps
和mergeProps
時基於各自的等值比較函式來比較所涉及到的state
和props
物件。 - [areStatesEqual] (Function): 如果引數
pure
為true
,用來比較傳入的store與之前的store值。預設值: strictEqual (===)。 - [areOwnPropsEqual] (Function):如果引數
pure
為true
,用來比較傳入的props與之前的props值。預設值: strictEqual (===)。 - [areStatePropsEqual] (Function):如果引數
pure
為true
,用以比較mapStateToProps
函式的結果與之前的結果值。 - [areMergedPropsEqual] (Function): 如果引數
pure
為true
,比較mergeProps
函式的結果與之前的值。預設值為:shallowEqual。 - [storeKey] (String): 用以從context獲取store的key值。你僅僅可能在有多個store值的情況下才需要這個選項,預設值為:
store
。
- [pure] (Boolean): 如果引數為true,用來避免重新渲染並呼叫
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
作為高階函式,返回connect
函式,通過柯里化的方式首先接受以下引數: connectHOC
、mapStateToPropsFactories
、mapDispatchToPropsFactories
、mergePropsFactories
與selectorFactory
。
connectHOC
傳入用來生成連線到store的高階元件(HOC),預設是之前介紹過的connectAdvanced
。
selectorFactory
selectorFactory
用來生成selector
,第一個引數將傳入connectAdvanced
。我們知道傳入connectAdvanced
的selectorFactory
函式主要是初始化selector函式。selector函式在每次connector component需要計算新的props都會被呼叫,selector函式會返回純物件(plain object),這個物件會作為props傳遞給被包裹的元件(WrappedComponent)。selectorFactory
的函式簽名為:
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
函式首先接受兩個引數,dispatch
和一系列的factoryOptions
,通過一系列的初始化函式分別生成了mapStateToProps
、mapDispatchToProps
、mergeProps
(初始化函式隨後會詳細介紹)。然後會在非生產環境下對上述三個函式進行驗證(驗證主要涉及到該函式是否為空和函式中是否有dependsOnOwnProps屬性,這個屬性隨後會介紹的)。隨後便是函式的重點部分,根據options.pure
是否為true,選擇恰當的selectorFactory
,然後返回selectorFactory(...args)
。
當options.pure
為false
時,selectorFactory
的值為:impureFinalPropsSelectorFactory
:
function impureFinalPropsSelectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps,
dispatch
) {
return function impureFinalPropsSelector(state, ownProps) {
return mergeProps(
mapStateToProps(state, ownProps),
mapDispatchToProps(dispatch, ownProps),
ownProps
)
}
}複製程式碼
我們知道,selectorFactory
會返回selector
函式,返回的函式會接受兩個引數:state
與ownProps
並最終返回屬性傳遞給被包裹的元件。我們發現impureFinalPropsSelectorFactory
非常的簡單,只是單純的將要求的引數傳遞給mapStateToProps
,mapDispatchToProps
,並將其結果連同ownProps
一起傳遞給mergeProps
,並將最後mergeProps
的結果作為selector
函式的結果。這個結果最終會傳遞給被包裹元件,這個函式沒有什麼難度而且非常符合connect
函式的API。
但我們知道在預設情況下,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)
}
}複製程式碼
函式pureFinalPropsSelectorFactory
中有一個閉包變數hasRunAtLeastOnce
用來判斷是否是第一次呼叫,如果selector
函式是第一次呼叫,selector
會返回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
的結果值。
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
}複製程式碼
再看函式handleSubsequentCalls
。其中areOwnPropsEqual
、areStatesEqual
分別用來判斷props和state現在的值與快取的值是否相等函式。handleSubsequentCalls
首先判斷state、props的前後值是否有變化,然後快取了state
、ownProps
。如果props和state都傳送改變了,返回handleNewPropsAndNewState
的結果,如果props
改變了,返回handleNewProps
的執行結果。如果state
改變,返回handleNewState
執行結果,否則如果state
和props
都沒發生改變,說明都沒有發生改變。直接返回之前快取的mergedProps
的值。
handleNewPropsAndNewState
定義如下:
function handleNewPropsAndNewState() {
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}複製程式碼
我們看到,如果props和state都傳送改變了,呼叫了handleNewPropsAndNewState
,首先就是執行mapStateToProps
返回stateProps
的值並快取,其次我們會根據mapDispatchToProps.dependsOnOwnProps
的值去判別是否執行mapDispatchToProps
。dependsOnOwnProps
的值主要是用來判別mapDispatchToProps
是否依賴於ownProps的值。最終執行mergeProps
函式,快取結果並傳入被包裹的元件。
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
將會非常簡單,分別去判別state
與dispatchProps
是否與ownProps相關。以判別是否需要重新執行mapStateToProps
和mapDispatchToProps
。最終將mergeProps
執行的值快取並傳遞給被包裹的元件。
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。根據是否state
變化,選擇性是否執行mergeProps
,最終返回mergedProps
給被包裹元件。
到現在為止,其實我們已經知道了selectorFactory
是與pure
值掛鉤的。如果pure
為true
的話,selectorFactory
返回的selector
會對state
和props
等值都會快取,然後會根據具體的場景,儘可能使得傳入被包裹元件的值改動最少(即儘可能返回相同的值),其目的就是減少不必要的渲染。當pure
為false
值,不會做任何的快取。
mapStateToProps起源
看完了selectorFactory
,我們需要去了解一下mapStateToProps
是怎麼來的:
//connect.js
// initMapStateToProps會被傳入 selectorFactory
const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, `mapStateToProps`)複製程式碼
//selectorFactory.js
const mapStateToProps = initMapStateToProps(dispatch, options)
//mapStateToProps的使用(注意這裡的mapStateToProps不是傳入的函式,而是init函式生成的函式):
const stateProps = mapStateToProps(state, ownProps)複製程式碼
我們可以看到,首先在connect.js
中通過match
函式取生成initMapStateToProps
。然後在selectorFactory
中,生成了mapStateToProps
的函式,然後會在selector
函式中使用mapStateToProps
生成了stateProps
,最後將stateProps
傳遞給被包裹的元件。
首先看match
函式的定義:
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}.`)
}
}複製程式碼
接下來的內容相對來說會比較複雜,我們先提前梳理一下match
函式的運作,其中factories
是一個陣列,它的實參將會是類似於mapStateToPropsFactories
(陣列)等值,然後args
將是你自定義的mapStateToProps
函式等值(比如mapStateToDispatch
)。我們將會以args
作為引數從後到前執行factories
陣列中的每一個函式,找到第一個返回不為假(類似於undefined
)的函式並且我們可以保證這個函式返回的是另一個函式,其簽名類似於:
(dispatch,options)=>{
//....
return ()=>{
}
}複製程式碼
這個返回的函式接受dispatch
和其他選項options
作為引數,最終返回一個函式供selector
使用的函式 ,比如mapStateToPropsFactories
一定會返回一個類似與於下面的函式:
(state, ownProps) =>{
//......
//return plain object
}複製程式碼
這個函式將用來計算新的state傳遞給被包裹的元件。
對於mapStateToProps
的來源要追溯到:
const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, `mapStateToProps`)複製程式碼
在函式match
中第一個實參是你傳入connect
的mapStateToProps
。第二個實參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
,如果是執行whenMapStateToPropsIsMissing
否則去執行whenMapStateToPropsIsFunction
。對於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
函式接受的引數是一個函式,這個函式負責在selector
返回一個常量作為props返回給被包裹元件。因為返回的總是一個常量,所以dependsOnOwnProps
為false
,表示返回給被包裹元件的值與連線到store的高階元件接受到的props
無關。
那麼whenMapStateToPropsIsMissing
函式呼叫wrapMapToPropsConstant
的引數是一個空函式(()=>{}
),那就說明在mapStateToProps
值為空(null
)的時候,是不給被包裹元件傳遞任何的屬性的。
whenMapStateToPropsIsFunction
的情況會比較複雜,如果傳入的mapStateToProps
是一個函式,那麼就會呼叫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
的函式相對來說比較複雜,接受的引數是你傳入的mapStateToProps
函式(methodName
的作用只是錯誤提示),返回的是初始化selector
函式(initProxySelector
)。當使用initProxySelector
初始化selector
的時候,返回的函式proxy
實則為一個代理(proxy
)。第一次執行proxy
(selector
)時,dependsOnOwnProps
的值為true
,所以相當於執行proxy.mapToProps(stateOrDispatch, ownProps)
(detectFactoryAndVerify
),然後將proxy.mapToProps
屬性設定為你所傳入的mapStateToProps
函式。這時候再去執行getDependsOnOwnProps
的目的是去確定你傳入的mapStateToProps
是否需要傳入props
。然後再去執行proxy(stateOrDispatch, ownProps)
,這時候proxy.mapToProps
已經不是之前的detectFactoryAndVerify
而是你傳入的mapStateToProps
(所以不會出現死迴圈)。執行的結果就是mapStateToProps
執行後的結果。如果prop
是物件,將會直接傳遞給被包裹元件。但是我們之前講過,mapStateToProps
是可以返回一個函式的,如果返回的值為一個函式,這個函式將會被作為proxy
的mapStateToProps
,再次去執行proxy
。
mapDispatchToProps起源
再去了解一下mapStateToProps
的來源:
//connect.js
const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, `mapDispatchToProps`)複製程式碼
//selectFactory
const mapDispatchToProps = initMapDispatchToProps(dispatch, options)
//使用:
const dispatchProps = mapDispatchToProps(dispatch, ownProps)複製程式碼
其實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
}複製程式碼
如果你已經看懂了wrapMapToPropsConstant
和wrapMapToPropsFunc
的函式的話,mapDispatchToPropsFactories
也就不難了。如果傳入的mapStateToProps
的值是一個物件的話,會呼叫whenMapDispatchToPropsIsObject
。繼而呼叫了wrapMapToPropsConstant
並傳入的引數是函式:dispatch => bindActionCreators(mapDispatchToProps, dispatch)
。根據我們之前經驗,那麼傳遞給被包裹的元件的屬性將是:bindActionCreators(mapDispatchToProps, dispatch)
的執行結果,即被dispatch
包裹的action
。
如果沒有傳入mapDispatchToProps
函式的話,呼叫whenMapDispatchToPropsIsMissing
。傳入函式wrapMapToPropsConstant
的引數為:dispatch => ({ dispatch })
,那麼被包裹的元件接受的引數即是store
的dispatch
方法。
如果傳入的mapDispatchToProps
是一個函式,呼叫whenMapDispatchToPropsIsFunction
函式。從而呼叫wrapMapToPropsFunc(mapDispatchToProps, `mapDispatchToProps`)
。執行的原理與執行wrapMapToPropsFunc(mapStateToProps, `mapStateToProps`)
基本相同,可以參照之前。
mergeProps起源
//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
函式,那麼呼叫函式whenMergePropsIsOmitted()
。到最後margedProps
函式即是defaultMergeProps
,defaultMergeProps
的定義為:
function defaultMergeProps(stateProps, dispatchProps, ownProps) {
return { ...ownProps, ...stateProps, ...dispatchProps }
}複製程式碼
如果你傳入了mapStateToProps
函式,呼叫函式whenMergePropsIsFunction()
,呼叫了wrapMergePropsFunc(mergeProps)
,其中引數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
中涉及到效能優化,首先wrapMergePropsFunc
返回一個初始mergeProps
的函式(mergePropsProxy
)。函式mergePropsProxy
閉包一個變數hasRunOnce
來記錄mergeProps
執行次數,在mergeProps
第一次執行時,會儲存第一次傳入被包裹元件的的props
,再以後的執行過程中,如果你傳入的引數pure
為true
並且前後的mergedProps
值不同時(比較函式你可以自定義)才會傳入新的屬性,否則將傳入之前的快取值,以此來優化不必要的渲染。
到此為止,我們基本已經在程式碼層面講完了connect
函式的原理,文章很長,有的地方可能相對比較難理解,建議大家都可以去從整體上看看react-redux
的原始碼。react-redux
原始碼解讀系列接下來會以其他的角度去分析react-redux
,歡迎大家繼續關注。