资讯专栏INFORMATION COLUMN

React Redux: 从文档看源码 - Connect工具类篇(2)

snowLu / 1775人阅读

摘要:负责记录所有的状态,以便在部分状态发生改变,而不影响组件渲染的时候,可以避免不必要的渲染。作用是,每次或发生改变以后,调用这个返回的,获取更新后的最终。由于发生改变,并不一定会造成返回结果的改变,所以需要根据检查后的结果来判定是否调用方法。

注:这篇文章只是讲解React Redux这一层,并不包含Redux部分。Redux有计划去学习,等以后学习了Redux源码以后再做分析
注:代码基于现在(2016.12.29)React Redux的最新版本(5.0.1)

Connect工具类篇(1)

Connect工具类篇(2) verifySubselectors.js

这里有四个参数:

mapStateToProps, mapDispatchToProps, mergeProps都是经过mapDispatchToProps, mapStateToProps, mergeProps封装过的

displayName是option里面传入的
主要做的是检查传入的mapStateToProps,mapDispatchToProps,mergeProps是否存在,由于这里的对象是经过几个map方法封装过的,所以不存在就说明开发传入的值是错误的。同时检查是否有dependsOnOwnProps这个属性,如果没有给一个warning.

import warning from "../utils/warning"

function verify(selector, methodName, displayName) {
  if (!selector) {
    throw new Error(`Unexpected value for ${methodName} in ${displayName}.`)

  } else if (methodName === "mapStateToProps" || methodName === "mapDispatchToProps") { //只检查mapStateToProps和mapDispatchToProps, 因为mergeProps方法不需要
    if (!selector.hasOwnProperty("dependsOnOwnProps")) {
      warning(
        `The selector for ${methodName} of ${displayName} did not specify a value for dependsOnOwnProps.`
      )
    }
  }
}

export default function verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps, displayName) {
  verify(mapStateToProps, "mapStateToProps", displayName)
  verify(mapDispatchToProps, "mapDispatchToProps", displayName)
  verify(mergeProps, "mergeProps", displayName)
}
selectorFactory.js

这里主要负责获取处理过的mapStateToProps, mapDispatchToProps, mergeProps和传入的options,来进行props的合并,最后返回合并后的结果。其中,当pure为true的时候,会对props进行存储,便于下一次比较,如果通过比较两个相同,那么就不改变props对象,减少不必要的re-render。

在connectAdvanced.js里面看到这么一段注释:

selectoryFactory方法返回的是一个function,这个function的作用是根据Redux Store state, props和dispatch计算新的props. 在connectAdvanced中会提供dispatch给selectorFactory,以便selectorFactory可以对actionCreator进行绑定。connectAdvanced获取的option配置会直接被传给selectorFactory,其中就包含了displayName和wrappedComponent(其实还有一些对比的方法在里面)。

selectorFactory负责记录所有的状态(props, store state, dispatch, mergedProps),以便在部分状态发生改变,而不影响组件渲染的时候,可以避免不必要的渲染。

finalPropsSelectorFactory
export default function 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
  )
}

这里只是给mapStateToProps, mapDispatchToProps, mergeProps传入dispatch和options对象,然后根据pure的值传给不同的方法进行处理。

如果pure是true, 那么selectorFactory返回的selector会负责存储最后结果。如果结果没有发生改变,那么connectAdvanced的shouldComponentUpdate就会返回false。

如果pure是false, 那么selector永远会返回一个新的对象,同时shouldComponentUpdate永远都返回true

这个factory方法会返回一个function,接收Redux Store和ownProps作为参数。作用是,每次store或ownProps发生改变以后,调用这个返回的function,获取更新后的最终props。

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

根据pure等于false的情况,这里会永远返回一个新的对象。存粹的、不加任何判断的调用mergeProps对几个props的结构进行合并。

这里返回的值的格式是:(state, ownProps)=>final props

pureFinalPropsSelectorFactory
export function pureFinalPropsSelectorFactory(
  mapStateToProps,
  mapDispatchToProps,
  mergeProps,
  dispatch,
  { areStatesEqual, areOwnPropsEqual, areStatePropsEqual }
) {
  let hasRunAtLeastOnce = false // 是否是第一次调用,第一次调用不需要做是否改变的检查
  let state // 记忆上一次的state
  let ownProps // 记忆上一次的ownProps
  let stateProps // 记忆mapStateToProps返回的props
  let dispatchProps // 记忆mapDispatchToProps返回的props
  let mergedProps // 记忆最后合并后的结果

  // 第一次调用的时候,纯粹记住所有的结果
  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
  }

  // 当两个都发生改变。。。
  function handleNewPropsAndNewState() {
    stateProps = mapStateToProps(state, ownProps) // ownProps发生了改变,肯定需要调用获取新的props

    if (mapDispatchToProps.dependsOnOwnProps)
      dispatchProps = mapDispatchToProps(dispatch, ownProps)

    mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
    return mergedProps
  }

  // 如果只有父组件传入的props发生了改变,那么需要根据dependsOnOwnProps来进行更新
  function handleNewProps() {
    if (mapStateToProps.dependsOnOwnProps)
      stateProps = mapStateToProps(state, ownProps)

    if (mapDispatchToProps.dependsOnOwnProps)
      dispatchProps = mapDispatchToProps(dispatch, ownProps)

    // 由于ownProps发生了改变,所以不需要进行检查,直接调用mergeProps方法
    mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
    return mergedProps
  }

  // 如果只有Redux store state发生了改变,那么只用更新mapStateToProps的返回值,因为dispatchProps和Redux State无关
  function handleNewState() {
    const nextStateProps = mapStateToProps(state, ownProps)
    const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps)
    stateProps = nextStateProps
    
    if (statePropsChanged)
      mergedProps = mergeProps(stateProps, dispatchProps, ownProps)

    return mergedProps
  }

  // 除第一次调用外,每次都需要对各种结果进行检查,然后记录必要的结果
  function handleSubsequentCalls(nextState, nextOwnProps) {
    const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps) // 检查ownProps是否发生改变
    const stateChanged = !areStatesEqual(nextState, state) // 检查Redux store state是否发生改变
    state = nextState
    ownProps = nextOwnProps

    // 根据改变的不同,调用不同的方法。减少不必要的运算
    if (propsChanged && stateChanged) return handleNewPropsAndNewState()
    if (propsChanged) return handleNewProps()
    if (stateChanged) return handleNewState()
    return mergedProps
  }

  return function pureFinalPropsSelector(nextState, nextOwnProps) {
    return hasRunAtLeastOnce
      ? handleSubsequentCalls(nextState, nextOwnProps)
      : handleFirstCall(nextState, nextOwnProps)
  }
}

当pure等于true的时候,需要做出各种检查来判定是否需要调用方法,来获取新的props.

当Redux state发生改变,ownProps没变的时候
1) 由于mapDispatchToProps并没有基于Redux State,所以dispatchProps是需要进行更新的。2) 而mapStateToProps是基于Redux State的,所以需要调用mapStateToProps方法或许"新的"stateProps。由于State发生改变,并不一定会造成返回结果的改变,所以需要根据检查后的结果来判定是否调用mergeProps方法。

当OwnProps发生改变,Redux State没有改变的时候
1) 由于mapDispatchToProps和mapStateToProps都可能基于ownProps,所以需要根据dependsOnOwnProps属性来检查,判断是否需要调用方法进行更新。2) ownProps作为mergeProps的一个必要参数,所以不需要做任何判断,mergePorps必须被调用

当Redux Store, OwnProps都发生了改变
综合之前的两点,mapStateToProps必须调用,mapDispatchToProps根据dependsOnOwnProps属性调用,mergeProps必须调用

一点总结:

在connect定义的时候,一般尽量使用pure:true的情况(默认值),因为在这种情况下,会对props进行差别检查。如果没有改变,就不会去调用connectAdvanced组件去更新。如果内部组件同时根据 父组件传入的propsRedux store的其他状态进行更新渲染,那么pure必须是false。

option中的areStatesEqual(默认值为===),areOwnPropsEqual(默认值为shallowEqual), areStatePropsEqual(默认值为shallowEqual), areMergedPropsEqual(默认值为shallowEqual),可以根据需要来修改这几个参数,当pure为true的时候,检查更多不必要的re-render

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88075.html

相关文章

  • React Redux: 文档源码 - Connect工具类篇(1)

    摘要:返回值决定了在更新的时候,是否要调用方法进行更新这里通过判断方法的来进行判断是否需要,当的时候,就是需要。同时,一个影对象会被造出并合并到组件的中。在这种情况下,返回的会被作为真正的。 注:这篇文章只是讲解React Redux这一层,并不包含Redux部分。Redux有计划去学习,等以后学习了Redux源码以后再做分析;注:代码基于现在 (2016.12.29) React Redu...

    pakolagij 评论0 收藏0
  • React Redux: 文档源码 - Components篇

    摘要:的作用在文档中是这么说的给下级组件中的提供可用的的对象。这个文件里的主要是被方法引入,并传给的,算是一个默认的。表示当前的名称。这个值表示在里面的值。便于控制,同时某些不需要渲染的,也不会造成渲染。 注:这篇文章只是讲解React Redux这一层,并不包含Redux部分。Redux有计划去学习,等以后学习了Redux源码以后再做分析注:代码基于现在(2016.12.29)React ...

    alphahans 评论0 收藏0
  • 精读《源码学习》

    摘要:精读原文介绍了学习源码的两个技巧,并利用实例说明了源码学习过程中可以学到许多周边知识,都让我们受益匪浅。讨论地址是精读源码学习如果你想参与讨论,请点击这里,每周都有新的主题,周末或周一发布。 1. 引言 javascript-knowledge-reading-source-code 这篇文章介绍了阅读源码的重要性,精读系列也已有八期源码系列文章,分别是: 精读《Immer.js》源...

    aboutU 评论0 收藏0
  • React 入门实践

    摘要:更多相关介绍请看这特点仅仅只是虚拟最大限度减少与的交互类似于使用操作单向数据流很大程度减少了重复代码的使用组件化可组合一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。在使用后,就变得很容易维护,而且数据流非常清晰,容易解决遇到的。 欢迎移步我的博客阅读:《React 入门实践》 在写这篇文章之前,我已经接触 React 有大半年了。在初步学习 React 之后就正式应用到项...

    shenhualong 评论0 收藏0
  • redux的一些笔记

    摘要:不只为组件提供中的数据及扩展方法,它还为定义的组件添加了一系列事件操作,这些事件的核心点就是,然后可以在自己定义的组件内获得。行为功能是对目的功能和有用行为的一种抽象。下一个中间件函数通常由名为的变量来表示。 redux 这个是好久之前写的,一直忘记粘过来,里面有一些是写作格式是我自己定义的,所以和segmentfault的markdown语法有出入,图片也不能加载,所以原文效果可以在...

    el09xccxy 评论0 收藏0

发表评论

0条评论

snowLu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<