庖丁解牛React-Redux(二): connect

connect API

  上篇文章庖丁解牛React-Redux(一): connectAdvanced介紹了react-redux的ProviderconnectAdvanced幾個重要API的原理,其中connectAdvancedconnect函數的基礎,這篇文章將主要介紹connect函數的原理。以前沒有閱讀過connectAdvanced最好提早閱讀一下這篇文章。以前的文章有讀者反映看起來比較晦澀,因此我準備隨後會出一篇關於相似圖解connectAdvanced的文章,不講代碼,主要從原理的方面詮釋connectAdvanced。再次作個廣告,歡迎你們關注個人掘金帳號和個人博客javascript

  最開始咱們仍是來介紹一下connect函數:
  java

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

  將React組件鏈接到Redux store,connect函數是connectAdvanced的正面,爲大多數常見場景提供了易於使用的API。connect函數並不會修改傳遞的組件,相反,它會返回一個新的,鏈接到store的組件類。react

參數:git

  • [mapStateToProps(state, [ownProps]): stateProps](Function):
    若是這個參數被傳遞,返回新的組件將會訂閱Redux的store的更新(update)。這意味着任什麼時候刻store更新,mapStateToProps將會被調用。mapStateToProps必須返回一個純對象(plain object),這個對象將會合並進組件的屬性(props)。若是你不想訂閱store的更新,能夠給mapStateToProps參數傳遞null或者undefinedgithub

若是你的mapStateToProps函數被聲明接受兩個參數,mapStateToProps在調用時第一個參數是store state,傳遞給鏈接組件(connected component)的屬性將會被做爲第二個參數。若是鏈接組件接受到新的props(淺比較),mapStateToProps也會再次調用。redux

注意: 在一些更高級的狀況下,你須要更好的控制渲染的性能,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,用來避免從新渲染並調用mapStateToPropsmapDispatchToPropsmergeProps時基於各自的等值比較函數來比較所涉及到的stateprops對象。

    • [areStatesEqual] (Function): 若是參數puretrue,用來比較傳入的store與以前的store值。默認值: strictEqual (===)。

    • [areOwnPropsEqual] (Function):若是參數puretrue,用來比較傳入的props與以前的props值。默認值: strictEqual (===)。

    • [areStatePropsEqual] (Function):若是參數puretrue,用以比較mapStateToProps函數的結果與以前的結果值。

    • [areMergedPropsEqual] (Function): 若是參數puretrue,比較mergeProps函數的結果與以前的值。默認值爲:shallowEqual。

    • [storeKey] (String): 用以從context獲取store的key值。你僅僅可能在有多個store值的狀況下才須要這個選項,默認值爲: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做爲高階函數,返回connect函數,經過柯里化的方式首先接受如下參數: connectHOCmapStateToPropsFactoriesmapDispatchToPropsFactoriesmergePropsFactoriesselectorFactory
 

connectHOC

  傳入用來生成鏈接到store的高階組件(HOC),默認是以前介紹過的connectAdvanced
  

selectorFactory

  selectorFactory用來生成selector,第一個參數將傳入connectAdvanced。咱們知道傳入connectAdvancedselectorFactory函數主要是初始化selector函數。selector函數在每次connector component須要計算新的props都會被調用,selector函數會返回純對象(plain object),這個對象會做爲props傳遞給被包裹的組件(WrappedComponent)。selectorFactory的函數簽名爲:

selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props (Function)

  咱們來看看reduxselectorFactory是怎麼定義的:
 

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,經過一系列的初始化函數分別生成了mapStateToPropsmapDispatchToPropsmergeProps(初始化函數隨後會詳細介紹)。而後會在非生產環境下對上述三個函數進行驗證(驗證主要涉及到該函數是否爲空和函數中是否有dependsOnOwnProps屬性,這個屬性隨後會介紹的)。隨後即是函數的重點部分,根據options.pure是否爲true,選擇恰當的selectorFactory,而後返回selectorFactory(...args)
  當options.purefalse時,selectorFactory的值爲:impureFinalPropsSelectorFactory:

function impureFinalPropsSelectorFactory(
  mapStateToProps,
  mapDispatchToProps,
  mergeProps,
  dispatch
) {
  return function impureFinalPropsSelector(state, ownProps) {
    return mergeProps(
      mapStateToProps(state, ownProps),
      mapDispatchToProps(dispatch, ownProps),
      ownProps
    )
  }
}

  咱們知道,selectorFactory會返回selector函數,返回的函數會接受兩個參數:stateownProps並最終返回屬性傳遞給被包裹的組件。咱們發現impureFinalPropsSelectorFactory很是的簡單,只是單純的將要求的參數傳遞給mapStateToPropsmapDispatchToProps,並將其結果連同ownProps一塊兒傳遞給mergeProps,並將最後mergeProps的結果做爲selector函數的結果。這個結果最終會傳遞給被包裹組件,這個函數沒有什麼難度並且很是符合connect函數的API。
  但咱們知道在默認狀況下,options.puretrue。所以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相比,只是作了緩存,保存了stateownProps以及mapStateToPropsdispatchPropsmergedProps的結果值。

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。其中areOwnPropsEqualareStatesEqual分別用來判斷props和state如今的值與緩存的值是否相等函數。handleSubsequentCalls首先判斷state、props的先後值是否有變化,而後緩存了stateownProps。若是props和state都發送改變了,返回handleNewPropsAndNewState的結果,若是props改變了,返回handleNewProps的運行結果。若是state改變,返回handleNewState運行結果,不然若是stateprops都沒發生改變,說明都沒有發生改變。直接返回以前緩存的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的值去判別是否運行mapDispatchToPropsdependsOnOwnProps的值主要是用來判別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
}

  理解了handleNewPropsAndNewStatehandleNewProps將會很是簡單,分別去判別statedispatchProps是否與ownProps相關。以判別是否須要從新運行mapStateToPropsmapDispatchToProps。最終將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值掛鉤的。若是puretrue的話,selectorFactory返回的selector會對stateprops等值都會緩存,而後會根據具體的場景,儘量使得傳入被包裹組件的值改動最少(即儘量返回相同的值),其目的就是減小沒必要要的渲染。當purefalse值,不會作任何的緩存。
  

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中第一個實參是你傳入connectmapStateToProps。第二個實參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返回給被包裹組件。由於返回的老是一個常量,因此dependsOnOwnPropsfalse,表示返回給被包裹組件的值與鏈接到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是能夠返回一個函數的,若是返回的值爲一個函數,這個函數將會被做爲proxymapStateToProps,再次去執行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
}

  若是你已經看懂了wrapMapToPropsConstantwrapMapToPropsFunc的函數的話,mapDispatchToPropsFactories也就不難了。若是傳入的mapStateToProps的值是一個對象的話,會調用whenMapDispatchToPropsIsObject。繼而調用了wrapMapToPropsConstant並傳入的參數是函數:dispatch => bindActionCreators(mapDispatchToProps, dispatch)。根據咱們以前經驗,那麼傳遞給被包裹的組件的屬性將是:bindActionCreators(mapDispatchToProps, dispatch)的運行結果,即被dispatch包裹的action

  若是沒有傳入mapDispatchToProps函數的話,調用whenMapDispatchToPropsIsMissing。傳入函數wrapMapToPropsConstant的參數爲:dispatch => ({ dispatch }),那麼被包裹的組件接受的參數便是storedispatch方法。
  
  若是傳入的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,再之後的運行過程當中,若是你傳入的參數puretrue而且先後的mergedProps值不一樣時(比較函數你能夠自定義)纔會傳入新的屬性,不然將傳入以前的緩存值,以此來優化沒必要要的渲染。

  到此爲止,咱們基本已經在代碼層面講完了connect函數的原理,文章很長,有的地方可能相對比較難理解,建議你們均可以去從總體上看看react-redux的源碼。react-redux源碼解讀系列接下來會以其餘的角度去分析react-redux,歡迎你們繼續關注。

相關文章
相關標籤/搜索