Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
MrErHu opened this issue Jul 25, 2017 · 0 comments
Open

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

MrErHu opened this issue Jul 25, 2017 · 0 comments
Labels

Comments

@MrErHu
Copy link
Owner

MrErHu commented Jul 25, 2017

connect API

  上篇文章庖丁解牛React-Redux(一): connectAdvanced介绍了react-redux的ProviderconnectAdvanced几个重要API的原理,其中connectAdvancedconnect函数的基础,这篇文章将主要介绍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,用来避免重新渲染并调用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,欢迎大家继续关注。

@MrErHu MrErHu added the Redux label Jul 25, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant