博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
react-redux源码解析
阅读量:6347 次
发布时间:2019-06-22

本文共 32552 字,大约阅读时间需要 108 分钟。

react-redux源码解析

react-redux作为大型react应用中链接react和redux的链接库,在很多reat项目中广泛应用。作为开发者的同学们了解reac-redux的原理和源码对我们的能力提升具有一定的帮助,所谓知其然知其所以然。

预备知识

(建议不知道connectAdvanced API,connectd的四个参数不是特别熟的同学先去简单过一下)

准备工作

老规矩github 找到 , clone master

本文版本: 6.0.0-beta.3复制代码

当然你也可以选择看笔者的, 其中包含redux和react-redux的源码及详细的注释

开始撸码

打开项目之后,其他的不多说了,我们直接看src里面的核心代码,从index.js 开始(哦, 这里插一嘴,react-redux是基于react和redux实现的,可以看一下package.json里面的peerDependencies)

一如既往的简单, 暴露出的Provider, connectAdvanced, connect 都有对应的api, 我们先来看看Provider的实现。

Provider实现

我们先想一想reac-redux都干了什么,简单来说用 < Provider >< /Provider>包装了根组件, 把 store 作为 props 传递到每一个被 connect() 包装的组件,其中state to props的计算过程做了优化。 react本身倡导props的自上而下单项传递,但是也提供context支持跨层级传递,到这里,聪明的你是不是联想到了provider与context有关呢,直接看?源码相关注释以添加

建议先看Provider.propTypes提供了那些props -> constructor -> render -> 声明周期钩子方法 -> 总结

import React, { Component } from 'react'import PropTypes from 'prop-types'import { ReactReduxContext } from './Context'class Provider extends Component {  constructor(props) {    super(props)    // 获取store    const { store } = props    // 初始化state, storeState为初始的redux state    this.state = {      storeState: store.getState(),      // 保存init store      store    }  }  componentDidMount() {    // 文件收索_isMounted, 共三处, componentWillUnmount中赋值为false    // 先假设为标记componentDidMount -> componentWillUnmount中    this._isMounted = true    // 来看下subscribe    this.subscribe()  }  componentWillUnmount() {    // 取消监听subscribe    if (this.unsubscribe) this.unsubscribe()    // 生命周期结束this._isMounted 赋值为false =>_isMounted假设成立✅    this._isMounted = false  }  componentDidUpdate(prevProps) {    // 如果更新之后,store的引用发生变化    if (this.props.store !== prevProps.store) {      // 如果存在监听则取消      if (this.unsubscribe) this.unsubscribe()      // 更新storeState      this.subscribe()    }    /*    * 在我的理解中redux的store应该是不变的,主要就是为了提供"全局变量state"    *   既然redux作者这样写,我们来思考一下为什么    *   一般store应该是这样 let store = createStore(rootReducer, initState,  applyMiddleware(xxx));    *   this.props.store !== prevProps.store说明全局的store发生了变化。既createStore方法的重新调用,    *   阅读过redux源码的同学应该知道, 既然是新的createStore, "全局的state"会发生变化,不再是之前的内存空间    *   所有这里再次调用subscribe更新state里面的storeState    *     * * */  }  // 使用store.subscribe方法,保证storeState的最新  subscribe() {    const { store } = this.props    // 监听subscribe    this.unsubscribe = store.subscribe(() => {     // 获取最新的state赋值给newStoreState      const newStoreState = store.getState()      // 不在本次生命周期中return      if (!this._isMounted) {        return      }      this.setState(providerState => {        // If the value is the same, skip the unnecessary state update.        // 如果state是相同的引用, 直接跳过state的更新        if (providerState.storeState === newStoreState) {          return null        }        // 更新当前storeState        return { storeState: newStoreState }      })    })        const postMountStoreState = store.getState()    if (postMountStoreState !== this.state.storeState) {      this.setState({ storeState: postMountStoreState })    }  }  render() {    // ReactReduxContext为默认context, 点过去看一下默认值。 看 -> context.js文件,createContext参数是null    const Context = this.props.context || ReactReduxContext    // value 为this.state    return (      
{this.props.children}
) }}Provider.propTypes = { // 接受store做为props, 并规定store object中的必要方法,既redux createStore的返回对象 store: PropTypes.shape({ subscribe: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired, getState: PropTypes.func.isRequired }), // 接收自定义context context: PropTypes.object, // children, 通常为根容器
children: PropTypes.any}export default Provider/** * provider总结 * * provider是react-redux提供是react应用的入口组件, 一般为顶层组件
* 使用react的context传递store, 老版本的provider用的getChildContext方法, 随着react context的api改变,生产者消费者模式的新api尤然而生,因此 * provider的源码已经重构, 提供的context为{ store, storeState: state},state保存为最新 * * * */复制代码

Context.js 提供全局的初始化ReactReduxContext

import React from 'react'// defaultValue 为 nullexport const ReactReduxContext = React.createContext(null)// export出来,以便提供给provider和consumer使用export default ReactReduxContext复制代码

connect 实现

先回顾一下connect的使用形式:

connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])(
)复制代码

这里还要了解一下connectAdvanced(selectorFactory, [connectOptions])方法,它是一个将 React 组件连接到 Redux store 的函数。这个函数是 connect() 的基础。

由于connect方法内引用文件,function及function的嵌套比较多,如果看官老爷不想过于在意细节,可以直接看一下

开始看connect源码 -> connect.js,简单看看结构和引用了哪些东西 ->然后我们从export default开始->遇到调用的function再去具体看实现了哪些功能

connect.js

/** *  先回顾一下connect的参数connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) *  作用:连接 React 组件与 Redux store *  mapDispatchToProps(dispatch, [ownProps]) *  *  react-redux 暴露的api, connectAdvanced(selectorFactory, [connectOptions]) *  连接react组件和redux的store, 这个参数是connect的基础*/import connectAdvanced from '../components/connectAdvanced'import shallowEqual from '../utils/shallowEqual'import defaultMapDispatchToPropsFactories from './mapDispatchToProps'// mapStateToProps(state, ownProps)// 只要 Redux store 发生改变,mapStateToProps 函数就会被调用, // 或者如果有ownProps参数组件接收到新的props,mapStateToProps同样会被调用import defaultMapStateToPropsFactories from './mapStateToProps'// mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中import defaultMergePropsFactories from './mergeProps'// 定制 connector 如 pure = true 等等等...import defaultSelectorFactory from './selectorFactory'/** * * 这里先以mapStatetoProps为例子, 其他的同理,简单了解后续用到再看 * @param {*} arg  使用时传进来的mapStatetoProps * @param {*} factories  array[function, function] * 默认工厂defaultMapStateToPropsFactories, [whenMapStateToPropsIsFunction, whenMapStateToPropsIsMissing] * @param {*} name  string * @returns  function */function match(arg, factories, name) {  // 后到前遍历factories  for (let i = factories.length - 1; i >= 0; i--) {    // 调用factories, 返回值赋值给result, 去看 -> mapStateToProps.js    const result = factories[i](arg)    // result为true返回result, result为(dispatch, options) => function(){...}的function    if (result) return result  }  // 不符合connect方法规则throw Error  return (dispatch, options) => {    throw new Error(      `Invalid value of type ${typeof arg} for ${name} argument when connecting component ${        options.wrappedComponentName      }.`    )  }}// 判断对象的索引是否相同function strictEqual(a, b) {  return a === b}// 暴露createConnect, 想必肯定会返回function因为connect是个functionexport function createConnect({  // 一些带有默认值的参数, 我们看下面, 具体用到了在看?  connectHOC = connectAdvanced, // connectAdvanced(selectorFactory, [connectOptions])  mapStateToPropsFactories = defaultMapStateToPropsFactories, // array[function, function]  mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,  mergePropsFactories = defaultMergePropsFactories,  selectorFactory = defaultSelectorFactory} = {}) {  // 返回的connect function  return function connect(    // connect的四个可选参数    mapStateToProps,    mapDispatchToProps,    mergeProps,    // 配置参数    {      pure = true, // 是否就行浅比较的配置      // 判断是否相同引用的function      areStatesEqual = strictEqual,       // shallowEqual 详情看下面?      areOwnPropsEqual = shallowEqual,      areStatePropsEqual = shallowEqual,      areMergedPropsEqual = shallowEqual,      // 其他配置项      ...extraOptions    } = {}  ) {    // mapStateToProps初始化    const initMapStateToProps = match(      // 使用时传递的mapStateToProps function      mapStateToProps,      // 默认值 -> 先看match方法, 然后我们来看mapStateToProps.js      mapStateToPropsFactories,      'mapStateToProps'    )    // mapDispatchToProps初始化    const initMapDispatchToProps = match(      mapDispatchToProps,      mapDispatchToPropsFactories,      'mapDispatchToProps'    )    // mergeProps的初始化    const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')    // return connectHOC function,将 React 组件连接到 Redux store 的函数    // 先来看看他的参数    // selectorFactory函数返回一个selector函数,根据store state, 展示型组件props,和dispatch计算得到新props,最后注入容器组件    // selectorFactory  -> defaultSelectorFactory    // 其实很熟悉react-redux api的同学应该很熟悉connectHOC的参数, 因为他就是connectAdvanced方法啊, 建议先看看api    return connectHOC(selectorFactory, {      // 用于错位信息      methodName: 'connect',      // 用Connect包装getDisplayName      getDisplayName: name => `Connect(${name})`,      // mapStateToProps是否为undefined,shouldHandleStateChanges为false则不监听store state      shouldHandleStateChanges: Boolean(mapStateToProps),      // selectorFactory需要的几个参数      initMapStateToProps,     // (dispatch, options) => initProxySelector(dispatch, { displayName }){...}      initMapDispatchToProps,      initMergeProps,      pure, // 默认true      // strictEqual, 这里很容易想到用于判断this.state是不是都一份引用      areStatesEqual,        // shallowEqual浅比较      // 插个题外话,熟悉react PureComponent的同学应该可以快速反应过来!shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState)      // 不熟悉的同学看过来 -> shallowEqual.js      areOwnPropsEqual,        areStatePropsEqual,      areMergedPropsEqual,      // 容错处理, 其他的配置项      ...extraOptions    })  }}// connect方法 直接调用createConnectexport default createConnect()复制代码

mapStateToProps.js

import { wrapMapToPropsConstant, wrapMapToPropsFunc } from './wrapMapToProps'// 当mapStateToProps为function时调用wrapMapToPropsFuncexport function whenMapStateToPropsIsFunction(mapStateToProps) {  return typeof mapStateToProps === 'function'    // 看wrapMapToPropsFunc -> wrapMapToProps.js    ? wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')    : undefined}// match中的数组倒着遍历先看这里// 容错处理, 判断是否传递mapStateToProps参数export function whenMapStateToPropsIsMissing(mapStateToProps) {  // 如果传递了mapStateToProps参数且!mapStateToProps = true返回undefined,此时result为undefined,无效调用  // 没有传递mapStateToProps参数或mapStateToProps=false -> wrapMapToPropsConstant  return !mapStateToProps ? wrapMapToPropsConstant(() => ({})) : undefined}// export default是array,元素为functionexport default [whenMapStateToPropsIsFunction, whenMapStateToPropsIsMissing]/** * 小结: *  * mapstateToprops参数可执行时调用wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps') * 不传递mapstateToprops参数时 wrapMapToPropsConstant(() => ({})) * 我们接着刨根问底 看->wrapMapToProps.js *  * * */复制代码

wrapMapToProps.js

import verifyPlainObject from '../utils/verifyPlainObject'/** * * @export  mapstateToprops为undefined调用 * @param {*} getConstant  () => ({}) * @returns  function initConstantSelector(dispatch, options) */export function wrapMapToPropsConstant(getConstant) {  // 返回 initConstantSelector  return function initConstantSelector(dispatch, options) {    const constant = getConstant(dispatch, options)     function constantSelector() {      return constant    }    constantSelector.dependsOnOwnProps = false    return constantSelector  }}// 用来判断是否存在ownProps // mapStateToProps(state, [ownProps])export function getDependsOnOwnProps(mapToProps) {  // 不是第一次调用直接返回Boolean  return mapToProps.dependsOnOwnProps !== null &&    mapToProps.dependsOnOwnProps !== undefined    ? Boolean(mapToProps.dependsOnOwnProps)    // 第一次调用时mapToProps的dependsOnOwnProps为undefined,直接判断参数个数    : mapToProps.length !== 1  }/** * @export  mapstateToprops传递时调用 * @param {*} mapToProps  使用connect是传递的mapStateToProprs * @param {*} methodName  名称  methodName = 'mapStatetoProps' || 'mapDispatchToProps' * @returns  返回initProxySelector(dispatch, { displayName }) */export function wrapMapToPropsFunc(mapToProps, methodName) {  // 终于找到你!! 返回initProxySelector function, 这个返回值会赋值给initMapStateToProps(当然还有initDispatchToProps)  return function initProxySelector(dispatch, { displayName }) {    // 定义proxy function,且作为返回值    const proxy = function mapToPropsProxy(stateOrDispatch, ownProps) {      return proxy.dependsOnOwnProps  // mapStateToProps计算是否依赖组件的props        ? proxy.mapToProps(stateOrDispatch, ownProps) //  返回proxy.mapToProps,继续看一下他是什么鬼?        : proxy.mapToProps(stateOrDispatch)    }    // dependsOnOwnProps标记运行依赖组件的props为true    proxy.dependsOnOwnProps = true    // detectFactoryAndVerify为返回的function    // 梳理一下,目前调用链是这样的    // const initMapStateToProps = initProxySelector(dispatch, { displayName })=>    //                             mapToPropsProxy(stateOrDispatch, ownProps) => detectFactoryAndVerify(stateOrDispatch, ownProps)    // detectFactoryAndVerify赋值给proxy.mapToProps    // 第一次调用 mapToPropsProxy时返回detectFactoryAndVerify(stateOrDispatch, ownProps)    proxy.mapToProps = function detectFactoryAndVerify(      stateOrDispatch,      ownProps    ) {      // 调用的时候 mapToPropsfunction 赋值给 proxy.mapToProps      // 也就是第一次除了调用到proxy.mapToProps之后, 以后在调用到proxy.mapToProps的时候则使用传递的mapToProps function      proxy.mapToProps = mapToProps      // 重新判断 dependsOnOwnProps(第一次默认true)      proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps)      // 定义props为proxy(stateOrDispatch, ownProps)      // 先看下执行顺序 第一次调用initProxySelector() => proxy() =>       // 此时 proxy.mapToProps = detectFactoryAndVerify()      // 再次调用 proxy(stateOrDispatch, ownProps)时 返回值为传递的mapToProps(...args),也就是我们react组件需要的props      let props = proxy(stateOrDispatch, ownProps)      // 如果props为function再次执行      if (typeof props === 'function') {        proxy.mapToProps = props        proxy.dependsOnOwnProps = getDependsOnOwnProps(props)        props = proxy(stateOrDispatch, ownProps)      }      // 非production环境检查      if (process.env.NODE_ENV !== 'production')        // verifyPlainObject是utils方法, 如果不是纯对象,抛出warning        verifyPlainObject(props, displayName, methodName)      // 返回最终的props      return props    }    return proxy  }}复制代码

mergeProps.js和mapDisptchToPtops.js同理,返回一个array[function,function],对参数做容错处理,返回一个initProxySelector function() => proxy => props, 具体细节后面介绍

shallowEqual

shallowEqual通常用来对object做浅比较,经常会出现在react应用中, 配合shouldComponentUpdate做性能优化, 如果熟悉PureComponent原理同学,那应该知道这段代码

!shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState)复制代码

shallowEqual.js

// 对象自身属性中是否具有指定的属性const hasOwn = Object.prototype.hasOwnProperty// 判断两个值是否是相同的值function is(x, y) {   // SameValue algorithm   if (x === y) {     return x !== 0 || y !== 0 || 1 / x === 1 / y;  } else {    return x !== x && y !== y;  }}// 浅比较 只会比较到两个对象的 ownProperty 是否符合 Object.is 判等,不会递归地去深层比较//    shallowEqual({x:{}},{x:{}}) // false//    shallowEqual({x:1},{x:1}) // trueexport default function shallowEqual(objA, objB) {  // 相同值直接返回true,shallowEqual返回值为boolean  if (is(objA, objB)) return true  // 在objA和objB不是相同值的前提下, 如果objA,objB为null或非object可以判定返回false  if (    typeof objA !== 'object' ||    objA === null ||    typeof objB !== 'object' ||    objB === null  ) {    return false  }  // 定义objA,objB的key数组  const keysA = Object.keys(objA)  const keysB = Object.keys(objB)  // length不同说明object不同  if (keysA.length !== keysB.length) return false  // 循环遍历keysA  for (let i = 0; i < keysA.length; i++) {    // 如果objB不含有objA的key且objA与objB的value不同, 返回false    if (!hasOwn.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {      return false    }  }  // 如果通过了for循环, 说明objA, objB中的第一层key和value都相同,恭喜通过  return true}复制代码

connect总结

由于connect函数设计的方法过多,我们在这里简化一下connect的代码(以下为源码的精简伪代码)

// 首先为以参数的形式为connect注入一些方法export function createConnect({ ...  // connectAdvanced为react-redux暴露出的api  connectHOC = connectAdvanced,  ...} = {}) {  // connect方法  return function connect(    // 接受的四个参数    mapStateToProps,    mapDispatchToProps,    mergeProps,    {      pure = true,  // 是否就行浅比较的配置      strictEqual,  // 判断object引用, strictEqual(a, b)=> a === b      shallowEqual, // 浅比较,上面介绍了      ...extraOptions  // 其他配置项    } = {}  ) {    // 一系列的方法执行,对三个参数的类型做了容错处理    // 分别初始化了各自的参数mapStateToProps,mapDispatchToProps,mergeProps,注入了一些内部的默认参数和方法    // 他们大致是这样的function:     // (dispatch, options) => initProxySelector() => mapToPropsProxy() => props    const initMapStateToProps = match(...args)    const initMapDispatchToProps = match(...args)    const initMergeProps = match(...args)    // 返回值由执行connectAdvanced获取,并传入初始化的initMapStateToProps等参数和pure等配置项    return connectAdvanced(selectorFactory, {      initMapStateToProps,      initMapDispatchToProps,      initMergeProps,      pure,      ...extraOptions    })  }} // 直接执行createConnect方法返回connectexport default createConnect()复制代码

connectAdvanced高阶函数

从connect()(<A/ >)中不难看出connect的返回值为一个高阶组件,包装当前的react组件,返回一个增强props的组件,在执行connect时会执行connectAdvanced,接下来我们不得不看下connectAdvanced方法的实现,先介绍一下connectAdvanced -> ?看注释

connectAdvanced.js

// hoist-non-react-statics组件,这个组件会自动把所有绑定在对象上的非React静态(static)方法都绑定到新的对象上import hoistStatics from 'hoist-non-react-statics'// 提示信息插件import invariant from 'invariant'import React, { Component, PureComponent } from 'react'import { isValidElementType } from 'react-is'// contextimport { ReactReduxContext } from './Context'/** * * @export  介绍下connectAdvanced *  connect() 的基础,真正将 React 组件连接到 Redux store 的函数 * @param {*} selectorFactory function  selectorFactory(dispatch, factoryOptions) *  初始化选择器函数,该选择器函数是在 connector 组件需要重新计算一个新的 props 时调用 *  作为 store 的 state 改变或者接收到一个新的 props 的结果。selector 的结果应该是一个普通对象, *  作为被包裹的组件的 props 传递。如果连续调用 selector 都返回与上一次调用相同的对象(===), *  则不会重新渲染该组件。selector 的责任是在适当的时候返回以前的对象。 * @param {*} [{ *     getDisplayName = name => `ConnectAdvanced(${name})`,  DisplayName *     methodName = 'connectAdvanced', *     renderCountProp = undefined, *     shouldHandleStateChanges = true, *     storeKey = 'store', *     withRef = false, *     context = ReactReduxContext, *     ...connectOptions *   }={}] * @returns */export default function connectAdvanced(   // function, 使用的时候在介绍selectorFactory.js  selectorFactory,  // options object:  {    // 被包裹的组件的 DisplayName 属性    getDisplayName = name => `ConnectAdvanced(${name})`,    // 用于显示错误消息    methodName = 'connectAdvanced',    // 组件是否订阅 redux store 的 state 更改    shouldHandleStateChanges = true,    renderCountProp = undefined, // 传递给内部组件的props键,表示render方法调用次数    // 可以获取 store 的 props/context key    storeKey = 'store',    // 如果为 true,则将一个引用存储到被包裹的组件实例中,并通过 getWrappedInstance() 方法使其可用    withRef = false,    // 看到这个变量我的第一反应是ref的转发, 不了解的同学去看一下React.forwardRef()    forwardRef = false,    // provider的ReactReduxContext方法    context = ReactReduxContext,    ...connectOptions  } = {}) {  // invariant 一个只在development环境的error  // When process.env.NODE_ENV is not production, the message is required.  // 这几个配置参数别使用的时候会有warnning,直接跳过这部分  invariant(    renderCountProp === undefined,    `renderCountProp is removed. render counting is built into the latest React dev tools profiling extension`  )  invariant(    !withRef,    'withRef is removed. To access the wrapped instance, use a ref on the connected component'  )  const customStoreWarningMessage =    'To use a custom Redux store for specific components,  create a custom React context with ' +    "React.createContext(), and pass the context object to React-Redux's Provider and specific components" +    ' like:  
. ' + 'You may also pass a {context : MyContext} option to connect' invariant( storeKey === 'store', 'storeKey has been removed and does not do anything. ' + customStoreWarningMessage ) // 定义Context const Context = context // 返回react高阶组件, WrappedComponent既包装的react组件 return function wrapWithConnect(WrappedComponent) { // 参数检验 if (process.env.NODE_ENV !== 'production') { invariant( isValidElementType(WrappedComponent), `You must pass a component to the function returned by ` + `${methodName}. Instead received ${JSON.stringify(WrappedComponent)}` ) } // 组件的displayName,默认Component const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component' // 拼接下displayName const displayName = getDisplayName(wrappedComponentName) // 定义selectorFactoryOptions对象,包含了connect和connectAdvanced的所有参数 const selectorFactoryOptions = { // connectOptions为initMapStateToProps,initMapDispatchToProps,pure等参数 ...connectOptions, getDisplayName, methodName, renderCountProp, shouldHandleStateChanges, storeKey, displayName, wrappedComponentName, WrappedComponent } // pure决定shouldComponentUpdate是否进行shwoEqual const { pure } = connectOptions // Component赋值给OuterBaseComponent, 用react高阶的继承 let OuterBaseComponent = Component // 定义FinalWrappedComponent let FinalWrappedComponent = WrappedComponent if (pure) { // 为true用PureComponent OuterBaseComponent = PureComponent } // 接下来直接看 class Connect extends OuterBaseComponent// function makeDerivedPropsSelector() { // 定义变量, 用来保存上一次makeDerivedPropsSelector中的值 // 变量语义化我们不难猜出意义 let lastProps let lastState let lastDerivedProps let lastStore let sourceSelector return function selectDerivedProps(state, props, store) { // props为父组件的props // pure为true时,props和state的引用都没有变化, 直接返回lastDerivedProps(第一次肯定不会成立) // 这里不难理解, 就是要求你用"纯"的state和props if (pure && lastProps === props && lastState === state) { return lastDerivedProps } if (store !== lastStore) { // store赋值lastStore, 更新lastStore // 除第一次调用外一般不会 lastStore = store // selectorFactory为connect传入的function,默认值来自selsctorFactory.js的export default sourceSelector = selectorFactory( store.dispatch, selectorFactoryOptions // 所有参数集合 ) } // props赋值给lastProps lastProps = props // state赋值给lastState lastState = state // 调用sourceSelector参入redux state和props, 得到最新的props // 不难看出selectorFactory的返回值为一个function, 目前我们可以猜测到 // selsctorFactory.js的export default function 大体结构是这样(dispatch, selectorFactoryOptions)=>(state, props) => newProps const nextProps = sourceSelector(state, props) // 新旧props引用相同 if (lastDerivedProps === nextProps) { // 直接返回 return lastDerivedProps } // 新旧props引用不相同, nextProps赋值给lastDerivedProps lastDerivedProps = nextProps // 返回lastDerivedProps return lastDerivedProps // 最后我们去看selsctorFactory.js到底如何合并的state和props } } function makeChildElementSelector() { // 定义props, ref, element变量 let lastChildProps, lastForwardRef, lastChildElement // 返回function return function selectChildElement(childProps, forwardRef) { // 判断新旧props, hre, elelment是否相同 if (childProps !== lastChildProps || forwardRef !== lastForwardRef) { // 如果不同重新赋值 lastChildProps = childProps lastForwardRef = forwardRef lastChildElement = ( // return FinalWrappedComponent, 改变props和ref
) } // react组件 return lastChildElement } } class Connect extends OuterBaseComponent { constructor(props) { super(props) invariant( forwardRef ? !props.wrapperProps[storeKey] : !props[storeKey], 'Passing redux store in props has been removed and does not do anything. ' + customStoreWarningMessage ) // 添加selectDerivedProps和selectChildElement方法 // selectDerivedProps为function是makeDerivedPropsSelector的返回值 this.selectDerivedProps = makeDerivedPropsSelector() // selectChildElement为function this.selectChildElement = makeChildElementSelector() // bind this this.renderWrappedComponent = this.renderWrappedComponent.bind(this) } // value为context,既provider中的{storeState: store.getState(),store} renderWrappedComponent(value) { invariant( value, `Could not find "store" in the context of ` + `"${displayName}". Either wrap the root component in a
, ` + `or pass a custom React context provider to
and the corresponding ` + `React context consumer to ${displayName} in connect options.` ) // 获取redux state和store const { storeState, store } = value // 定义wrapperProps为this.props let wrapperProps = this.props let forwardedRef // forwardRef为真时, Connect组件提供了forwardedRef = {ref} if (forwardRef) { // wrapperProps为props中的wrapperProps wrapperProps = this.props.wrapperProps // forwardedRef赋值为props的forwardedRef, 传递的是ref // 用于传递给子组件WrappedComponent既let FinalWrappedComponent = WrappedComponent中的FinalWrappedComponent forwardedRef = this.props.forwardedRef } // 导出props let derivedProps = this.selectDerivedProps( storeState, wrapperProps, store ) // 返回最终的组件,传入最终的props和ref -> 看selectChildElement发放 return this.selectChildElement(derivedProps, forwardedRef) } render() { // 默认情况下公用的ReactReduxContext const ContextToUse = this.props.context || Context return ( //
的消费者
{
this.renderWrappedComponent}
) } } // 相当于插件 // 包装的组件赋值给Connect.WrappedComponent Connect.WrappedComponent = WrappedComponent // 添加displayName Connect.displayName = displayName // forwardRef为true时 if (forwardRef) { // 使用react.forwardRef为connect生成的组件的父组件提供孙子(传递给connect的组件)组件 const forwarded = React.forwardRef(function forwardConnectRef( props, ref ) { return
}) // 此时connect()(
)的生成组件为forwarded, 从新挂载displayName和WrappedComponent forwarded.displayName = displayName forwarded.WrappedComponent = WrappedComponent return hoistStatics(forwarded, WrappedComponent) } // 将子组件的非React的static(静态)属性或方法合并到父组件 // 返回拓展过props属性的Connect组件 return hoistStatics(Connect, WrappedComponent) }}复制代码

connectAdvanced返回一个react高阶组件, 根据pure,forwardRef配置决定是否采用PureComponent和ref的转移, 通过selectDerivedProps放法生成最终的props,传递给最终返回的react组件,最后我们去看selsctorFactory.js到底如何合并的state和props

selectorFactory

selectorFactory函数返回一个selector函数,根据store state, 展示型组件props和dispatch计算得到新props,最后注入容器组件中

selectorFactory.js实现

import verifySubselectors from './verifySubselectors'export function impureFinalPropsSelectorFactory(  mapStateToProps,  mapDispatchToProps,  mergeProps,  dispatch) {  return function impureFinalPropsSelector(state, ownProps) {    // 执行mergePropsProxy,返回修改后的props    return mergeProps(      mapStateToProps(state, ownProps),  // mapStateToProps执行结果      mapDispatchToProps(dispatch, ownProps), // mapDispatchToProps的执行结果      ownProps // 自身的props    )  }}export function pureFinalPropsSelectorFactory(  mapStateToProps,  mapDispatchToProps,  mergeProps,  dispatch,  // areStatesEqual判断是否是相同的引用  // areOwnPropsEqual, areStatePropsEqual为shallowEqual  { areStatesEqual, areOwnPropsEqual, areStatePropsEqual }) {  // hasRunAtLeastOnce标记第一次执行  // 先看return的function,再看其他的function都做了什么  let hasRunAtLeastOnce = false  let state  let ownProps  let stateProps  let dispatchProps  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    hasRunAtLeastOnce = true    // 返回mergedProps    return mergedProps  }  function handleNewPropsAndNewState() {    // 获取当前新的的state    stateProps = mapStateToProps(state, ownProps)    if (mapDispatchToProps.dependsOnOwnProps)      dispatchProps = mapDispatchToProps(dispatch, ownProps)    // 返回mergedProps function内部为新的object    mergedProps = mergeProps(stateProps, dispatchProps, ownProps)    return mergedProps  }  // 自身props改变  function handleNewProps() {    // dependsOnOwnProps之前介绍过,判断是否有第一个参数ownprops    // 如果存在需要重新执行,获取新的stateProps和mapDispatchToProps,因为自身的props改变了    if (mapStateToProps.dependsOnOwnProps)      stateProps = mapStateToProps(state, ownProps)    if (mapDispatchToProps.dependsOnOwnProps)      dispatchProps = mapDispatchToProps(dispatch, ownProps)    mergedProps = mergeProps(stateProps, dispatchProps, ownProps)    return mergedProps  }  // redux state改变  function handleNewState() {    const nextStateProps = mapStateToProps(state, ownProps)    // 浅比较nextStateProps和stateProps    const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps)    // 更新stateProps    stateProps = nextStateProps    //statePropsChanged为ture,浅比较失败,mergedProps需要重新计算,mergedProps返回新对象    if (statePropsChanged)      mergedProps = mergeProps(stateProps, dispatchProps, ownProps)    return mergedProps  }  function handleSubsequentCalls(nextState, nextOwnProps) {    // 执行的时候ownProps浅比较    const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps)    // 比较redux state的引用    const stateChanged = !areStatesEqual(nextState, state)    // nextState赋值给state    state = nextState    // nextOwnProps赋值给onwProps    ownProps = nextOwnProps    // props && state change    // 看不同情况对应的return function    if (propsChanged && stateChanged) return handleNewPropsAndNewState()    // props change    if (propsChanged) return handleNewProps()    // state change    if (stateChanged) return handleNewState()    // propsChanged, stateChanged为true认为props,state没有改变,return mergedProps    return mergedProps  }  return function pureFinalPropsSelector(nextState, nextOwnProps) {  // state props    return hasRunAtLeastOnce // 默认值为false      ? handleSubsequentCalls(nextState, nextOwnProps)      : handleFirstCall(nextState, nextOwnProps)  }}// 找到export default/** * * * @export * @param {*} dispatch // store.dispatch * @param {*} {  *    initMapStateToProps // 结构initProxySelector(dispatch, { displayName }) => proxy *    initMapDispatchToProps, // 结构 initMergePropsProxy(dispatch, options) => mergePropsProxy  *    initMergeProps,  *    ...options    其他配置 *  } * @returns  selectorFactory function  */// finalPropsSelectorFactory和我们的设想结构一致export default function finalPropsSelectorFactory(  dispatch,    { initMapStateToProps, initMapDispatchToProps, initMergeProps, ...options }) {  // 调用initProxySelector得到proxy function, proxy包含mapToProps, dependsOnOwnProps属性  const mapStateToProps = initMapStateToProps(dispatch, options)  const mapDispatchToProps = initMapDispatchToProps(dispatch, options)  // mergePropsProxy为function  // 返回值为connect(mapstate,mapdispatch,function mergeProps(){})()中mergeProps的返回值  const mergeProps = initMergeProps(dispatch, options)  // 非production环境检验 mapStateToProps,mapDispatchToProps,mergeProps  if (process.env.NODE_ENV !== 'production') {    verifySubselectors(      mapStateToProps,      mapDispatchToProps,      mergeProps,      options.displayName    )  }  // pure为true时表示selectorFactory的返回值缓存, 根据当前的redux state和ownProps的变化尽量做最出小的改变  // 详情看pureFinalPropsSelectorFactory  // 否则返回新对象  const selectorFactory = options.pure    ? pureFinalPropsSelectorFactory    : impureFinalPropsSelectorFactory  // 执行selectorFactory  // selectorFactory为工厂函数,返回selector  return selectorFactory(    mapStateToProps,    mapDispatchToProps,    mergeProps, // function mergePropsProxy    dispatch,    options  )}复制代码

mergedProps实现

import verifyPlainObject from '../utils/verifyPlainObject'export function defaultMergeProps(stateProps, dispatchProps, ownProps) {  // 返回一个新对象  return { ...ownProps, ...stateProps, ...dispatchProps }}export function wrapMergePropsFunc(mergeProps) {  // initMergeProps  return function initMergePropsProxy(    dispatch,    { displayName, pure, areMergedPropsEqual }  ) {    // 第一次运行,设置为false    let hasRunOnce = false    let mergedProps    return function mergePropsProxy(stateProps, dispatchProps, ownProps) {      // mergeProps的返回结果      const nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps)      if (hasRunOnce) {        // pure为fales 或者mergedProps为null        if (!pure || !areMergedPropsEqual(nextMergedProps, mergedProps))          mergedProps = nextMergedProps      } else {        // 不是第一次运行,hasRunOnce标记为false        hasRunOnce = true        // nextMergedProps赋值给mergedProps        mergedProps = nextMergedProps        if (process.env.NODE_ENV !== 'production')          verifyPlainObject(mergedProps, displayName, 'mergeProps')      }     // 返回修改后的props      return mergedProps    }  }}export function whenMergePropsIsFunction(mergeProps) {  // 如果mergeProps为true且是function, 调用wrapMergePropsFunc返回function initMergePropsProxy(){}  return typeof mergeProps === 'function'    ? wrapMergePropsFunc(mergeProps)    : undefined}export function whenMergePropsIsOmitted(mergeProps) {  // mergeProps !== true retun () => { ...ownProps, ...stateProps, ...dispatchProps }  return !mergeProps ? () => defaultMergeProps : undefined}// 后向前执行export default [whenMergePropsIsFunction, whenMergePropsIsOmitted]/** * [mergeProps(stateProps, dispatchProps, ownProps): props] (Function): *  如果指定了这个参数,mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。 *  该回调函数返回的对象将作为 props 传递到被包装的组件中 */复制代码

转载于:https://juejin.im/post/5c0e2a616fb9a049a9798997

你可能感兴趣的文章
成为世界第三大运动品牌还不满足 安踏想要占领你的“心智”
查看>>
程序员写300行代码获1.5万月薪,网友:我可以敲到公司破产
查看>>
重要宣布:Flutter 首个发布预览版
查看>>
广东移动与阿里巴巴宣布共建反诈实验室
查看>>
[译] Laravel-mix 3.0 中文文档
查看>>
深入理解Java SPI之入门篇
查看>>
机器学习之决策树
查看>>
我的阿里之路+Java面经考点
查看>>
Kotlin——中级篇(四):继承类详解
查看>>
windows10 chrome 调试 ios safari 方法
查看>>
QML学习笔记(七)-如何查看帮助手册中的控件例子
查看>>
旧手机的新玩法:postmarketOS 已适配上百款安卓手机
查看>>
InitAdmin 201904 更新,首创云后台概念
查看>>
jvm系列文章
查看>>
Countly 19.02.1 发布,实时移动和 web 分析报告平台
查看>>
自定义 标签
查看>>
百度贴吧发贴回贴POST接口
查看>>
【Recorder.js+百度语音识别】全栈方案技术细节
查看>>
PS背后的神秘AI力量 是Adobe憋了十年的神功
查看>>
加速Web自动化测试
查看>>