react-redux源码

index.js

import Provider from './components/Provider'
import connectAdvanced from './components/connectAdvanced'
import connect from './connect/connect'

export { Provider, connectAdvanced, connect }

Provide.js

import { Component, PropTypes, Children } from 'react'
// 传入Subscription的意义及用法???
import Subscription from '../utils/Subscription'
import storeShape from '../utils/storeShape'
import warning from '../utils/warning'

// 开发环境下,组件更新时store变更,打印错误
let didWarnAboutReceivingStore = false
function warnAboutReceivingStore() {
    if (didWarnAboutReceivingStore) {
        return
    }
    didWarnAboutReceivingStore = true

    warning(
        '<Provider> does not support changing `store` on the fly. ' +
        'It is most likely that you see this error because you updated to ' +
        'Redux 2.x and React Redux 2.x which no longer hot reload reducers ' +
        'automatically. See https://github.com/reactjs/react-redux/releases/' +
        'tag/v2.0.0 for the migration instructions.'
    )
}

// Provider作为容器组件,向子组件上下文对象context注入props.store,即Redux的store
export default class Provider extends Component {
    getChildContext() {
        return { store: this.store, storeSubscription: null }
    }

    constructor(props, context) {
        super(props, context)
        this.store = props.store
    }

    render() {
        return Children.only(this.props.children)
    }
}

if (process.env.NODE_ENV !== 'production') {
    Provider.prototype.componentWillReceiveProps = function (nextProps) {
        const { store } = this
        const { store: nextStore } = nextProps

        if (store !== nextStore) {
            warnAboutReceivingStore()
        }
    }
}

Provider.propTypes = {
    store: storeShape.isRequired,
    children: PropTypes.element.isRequired
}
Provider.childContextTypes = {
    store: storeShape.isRequired,
    storeSubscription: PropTypes.instanceOf(Subscription)
}
Provider.displayName = 'Provider'

connect.js

// connectAdvanced函数由connect模块内部调用,铰链redux.store和react组件
//    目的是通过react.props获取redux.state、redux.dispatch(action)的相关特征,传输数据流和派发事件
//    同时获得redux.dispatch特征的props.actionname派发事件时,触发react.props重新计算和组件视图重绘
// 返回函数接受react组件构造函数为参数,用以形成高阶组件,作为视图层render方法渲染的参数
import connectAdvanced from '../components/connectAdvanced'

// 比较变量是否全等,或者普通对象单层比较是否相同
import shallowEqual from '../utils/shallowEqual'

// 当用户配置的mapDispatchToProps是函数时,使用wrapMapToPropsFunc装饰mapDispatchToProps
//    传入redux的dispatch方法、react组件的displayName
// 当用户配置的mapDispatchToProps不是函数时,设置默认的mapDispatchToProps为输出redux.store.dispatch方法;否则不设置
// 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
// 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性
import defaultMapDispatchToPropsFactories from './mapDispatchToProps'

// 当用户配置的mapStateToProps是函数时,使用wrapMapToPropsFunc装饰mapStateToProps
//    传入redux的dispatch方法、react组件的displayName
// 当用户配置的mapStateToProps不是函数时,设置默认的mergeProps为空函数;否则不设置
// 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
// 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性Props为空函数;否则不设置
import defaultMapStateToPropsFactories from './mapStateToProps'

// 当用户配置的mergeProps是函数时,使用wrapMergePropsFunc装饰mergeProps
//    传入redux的dispatch方法、react组件的displayName、pure、areMergedPropsEqual
// 当用户配置的mergeProps不是函数时,设置默认的mergeProps为defaultMergeProps
// 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
// 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性Props为空函数;否则不设置
import defaultMergePropsFactories from './mergeProps'

// 传入connectAdvanced模块
// 函数,以redux.store.dispatch、react.options为参数,返回react.props计算函数
import defaultSelectorFactory from './selectorFactory'

// factories为数组形式的函数队列,用于装饰用户配置的mapStateToProps、mapDispatchToProps、mergeProps(作为参数)
// 根据参数为空、为函数、为对象,按条件构造装饰函数构造器
//     该构造器接受相应redux的dispatch方法及react组件的options属性与方法
//     并传入mapStateToProps、mapDispatchToProps、mergeProps函数中,或redux方法改造mapDispatchToProps函数
//     完成装饰,最终结果是赋予react组件的props,以redux.store.state,redux.store.dispatch的方法与属性
// 针对react组件更新重绘的情形,这一过程由挂载在react组件props上的redux.store.dispatch引起
//     通过挂载在react组件上的this.selector.run重新计算props,获取redux.store.state,redux.store.dispatch
//     this.selector.run在react组件上挂载this.subscription实例的onStateChange方法上调用
//     而本层组件的onStateChange方法通过redux.store.subscribe绑定为回调函数
//          同时本层组件的onStateChange触发this.subscription.notifyNestedSubs方法
//          而子组件的onStateChange通过this.subscription.addNestedSub绑定为回调函数
//          这样redux.store.dispatch就可以触发父子组件的props更新
//     最终调用react组件的setState方法重绘组件
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}.`)
    }
}

// 判断是否完全相等
function strictEqual(a, b) { return a === b }

// createConnect函数通常为内部调用,各参数均为默认值;这样处理的好处是便于模块化,在各模块中设置默认值
export function createConnect({
    connectHOC = connectAdvanced,
    mapStateToPropsFactories = defaultMapStateToPropsFactories,
    mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
    mergePropsFactories = defaultMergePropsFactories,
    selectorFactory = defaultSelectorFactory
} = {}) {

    // connect函数作为外部api接口,各参数均由用户传入;返回函数,接受待包装的react组件作为参数
    // 通过内部调用connectHOC(selectorFactory,options)(basicComponent)构造基于react组件的高阶组件basicComponent
    // 该组件赋予selector属性,其中selector.run方法用于重新计算props
    //    计算props的过程,需要通过传入当前redux.store的dispatch方法、高阶组件属性options
    //    借此装饰用户配置mapStateToProps、mapDispatchToProps、mergeProps函数,mapDispatchToProps可以是对象
    // 该组件赋予subscription属性,通过subscription.onStateChange作为redux.store.dispatch的直接或间接回调函数
    //    而subscription.onStateChange内部调用react.selector.run重新计算样式值、react.setState重绘组件
    // 注:用户配置的mapStateToProps、mapDispatchToProps为函数,可添加dependsOnOwnProps属性
    //    当其为真值时,意味通过redux的state、dispatch更新react组件的props时,需要原有的props作为参数 

    // mapStateToProps将redux.store.state映射给props,store.state变动引起props相应变动
    //    示例:redux.store.state改变,将引起props.todos属性作相应改变
    // const mapStateToProps = (state) => {
    //   return {
    //     todos: getVisibleTodos(state.todos, state.visibilityFilter)
    //   }
    // }
    // const getVisibleTodos = (todos, filter) => {
    //   switch (filter) {
    //     case 'SHOW_ALL':
    //       return todos
    //     case 'SHOW_COMPLETED':
    //       return todos.filter(t => t.completed)
    //     case 'SHOW_ACTIVE':
    //       return todos.filter(t => !t.completed)
    //     default:
    //       throw new Error('Unknown filter: ' + filter)
    //   }
    // }

    // mapDispatchToProps将redux.store.dispatch映射给props,便于通过props[actionname]调用redux.store.dispatch方法
    //    示例1:可通过props.onClick()触发redux事件机制,即通过dispatch派发action
    //          dispatch方法由装饰函数传入
    //          mapDispatchToProps为函数形式,待装饰,才可以传入dispatch方法
    // const mapDispatchToProps = (
    //   dispatch,
    //   ownProps
    // ) => {
    //   return {
    //     onClick: () => {
    //       dispatch({
    //         type: 'SET_VISIBILITY_FILTER',
    //         filter: ownProps.filter
    //       });
    //     }
    //   };
    // }
    //    示例2:props.onClick()将通过react-redux内部机制自动调用dispatch派发action,action由mapDispatchToProps构造
    //          装饰过程中调用redux的bindActionCreators生成用于派发相应action的方法,内部调用dispatch方法
    //          mapDispatchToProps为对象形式,才可以调用redux的bindActionCreators方法
    //  const mapDispatchToProps = {
    //   onClick: (filter) => {
    //     type: 'SET_VISIBILITY_FILTER',
    //     filter: filter
    //   };
    // }
    return function connect(
        mapStateToProps,
        mapDispatchToProps,
        mergeProps,
        // 可重写的属性包括areStatesEqual、areOwnPropsEqual、areStatePropsEqual、areMergedPropsEqual
        //    以及methodName(错误提示用)、等
        {
            // 真值时,redux.dispatch派发action事件触发时,将优化react.props计算方案
            // 否值时,傻瓜式重新计算react.props
            pure = true,

            // 默认判断redux.state是否修改,需要重新将redux.state、redux.dispatch按条件赋值给react.props
            // 用户重写判断机制,可以实现修改redux.state部分属性时,避过react-redux通过redux.store重新计算props
            areStatesEqual = strictEqual,

            // 默认判断react.props是否修改,需要重新,需要重新将redux.state、redux.dispatch按条件赋值给react.props
            // 用户重写判断机制,可以实现修改react.props部分属性时,避过react-redux通过redux.store重新计算props
            areOwnPropsEqual = shallowEqual,

            // 由mapStateToProps函数获得的stateProps是否与前一次相同,可避免react.props的重新赋值
            areStatePropsEqual = shallowEqual,

            // 由redux.state、redux.dispatch混合构造的mergeProps是否与前一次相同,可避免react.props的重新赋值
            areMergedPropsEqual = shallowEqual,
            ...extraOptions
        } = {}
    ) {

          // 当用户配置的mapStateToProps是函数时,使用wrapMapToPropsFunc装饰mapStateToProps
          //    传入redux的dispatch方法、react组件的displayName
          // 当用户配置的mapStateToProps不是函数时,设置默认的mergeProps为空函数;否则不设置
          // 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
          // 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性Props为空函数;否则不设置
          const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps')
          
          // 当用户配置的mapDispatchToProps是函数时,使用wrapMapToPropsFunc装饰mapDispatchToProps
          //    传入redux的dispatch方法、react组件的displayName
          // 当用户配置的mapDispatchToProps不是函数时,设置默认的mapDispatchToProps为输出redux.store.dispatch方法;否则不设置
          // 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
          // 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性
          const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps')
          
          // 当用户配置的mergeProps是函数时,使用wrapMergePropsFunc装饰mergeProps
          //    传入redux的dispatch方法、react组件的displayName、pure、areMergedPropsEqual
          // 当用户配置的mergeProps不是函数时,设置默认的mergeProps为defaultMergeProps
          // 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
          // 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性Props为空函数;否则不设置
          const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')

          return connectHOC(selectorFactory, {
              methodName: 'connect',// 用于错误提示

               // used to compute Connect's displayName from the wrapped component's displayName.
              getDisplayName: name => `Connect(${name})`,

              // react.store.dispatch(外部接口为react.props.actionname)触发改变props,是否重绘组件
              shouldHandleStateChanges: Boolean(mapStateToProps),

              initMapStateToProps,
              initMapDispatchToProps,
              initMergeProps,
              pure,
              areStatesEqual,
              areOwnPropsEqual,
              areStatePropsEqual,
              areMergedPropsEqual,

              ...extraOptions
        })
    }

}

export default createConnect()

connectAdvanced.js

import hoistStatics from 'hoist-non-react-statics'
import invariant from 'invariant'
import { Component, PropTypes, createElement } from 'react'

// 通过向react组件挂载this.subscription对象
// 将当前组件及其子孙组件的subscription.onStateChange绑定为redux.stroe.dispatch方法的回调
// subscription.onStateChange方法中,调用this.selector.run重新计算props
// 本层组件的onStateChange方法通过redux.store.subscribe绑定为回调函数
//     同时本层组件的onStateChange触发this.subscription.notifyNestedSubs方法
//     而子组件的onStateChange通过this.subscription.addNestedSub绑定为回调函数
// 这样redux.store.dispatch就可以触发父子组件的props更新
import Subscription from '../utils/Subscription'

import storeShape from '../utils/storeShape'

let hotReloadingVersion = 0

// connectAdvanced函数由connect模块内部调用,铰链redux.store和react组件
//    目的是通过react.props获取redux.state、redux.dispatch(action)的相关特征,传输数据流和派发事件
//    同时获得redux.dispatch特征的props.actionname派发事件时,触发react.props重新计算和组件视图重绘
// 返回函数接受react组件构造函数为参数,用以形成高阶组件,作为视图层render方法渲染的参数

// 首参selectorFactory默认为selectorFactory模块
//    用于定义最终装饰函数mapStateToProps、mapDispatchToProps、mergeProps的执行机制
//    通过redux、react相关树形,构造react.props计算函数
// 次参options对象,相关配置
export default function connectAdvanced(
    selectorFactory,

    {
        // the func used to compute this HOC's displayName from the wrapped component's displayName.
        // probably overridden by wrapper functions such as connect()
        getDisplayName = name => `ConnectAdvanced(${name})`,

        // 错误提示用
        methodName = 'connectAdvanced',

        // if defined, the name of the property passed to the wrapped element indicating the number of
        // calls to render. useful for watching in react devtools for unnecessary re-renders.
        renderCountProp = undefined,

        // redux.store.state初始化赋值、redux.store.dispatch方法触发时引起store.state变更,是否影响组件的props
        // 默认影响,shouldHandleStateChanges置为false时不影响,即redux监听state变更不影响react视图渲染
        // 用户使用react-redux,shouldHandleStateChanges由用户配置的mapStateToProps是否为真值决定
        shouldHandleStateChanges = true,

        // the key of props/context to get the store
        storeKey = 'store',

        // if true, the wrapped element is exposed by this HOC via the getWrappedInstance() function.
        withRef = false,

        // additional options are passed through to the selectorFactory
        ...connectOptions
    } = {}
) {
    const subscriptionKey = storeKey + 'Subscription'
    const version = hotReloadingVersion++

    const contextTypes = {
        [storeKey]: storeShape,
        [subscriptionKey]: PropTypes.instanceOf(Subscription),
    }
    const childContextTypes = {
        [subscriptionKey]: PropTypes.instanceOf(Subscription)
    }

    // 用户设置connect(mapStateToProps,mapDispatchToProps)(component)中component
    // 构成高阶组件
    return function wrapWithConnect(WrappedComponent) {
        invariant(
            typeof WrappedComponent == 'function',
            `You must pass a component to the function returned by ` +
            `connect. Instead received ${WrappedComponent}`
        )

        const wrappedComponentName = WrappedComponent.displayName
            || WrappedComponent.name
            || 'Component'

        const displayName = getDisplayName(wrappedComponentName)

        const selectorFactoryOptions = {
            ...connectOptions,
            getDisplayName,
            methodName,
            renderCountProp,
            shouldHandleStateChanges,
            storeKey,
            withRef,
            displayName,
            wrappedComponentName,
            WrappedComponent
        }

        class Connect extends Component {
            constructor(props, context) {
                super(props, context)

                this.version = version
                this.state = {}
                this.renderCount = 0
                // Provider容器组件中,通过context.store向子组件传入Redux的store,storeKey默认为store
                // 未曾设置Provider的情形下呢????
                this.store = this.props[storeKey] || this.context[storeKey]
                // 父组件的subscription回调队列属性,当前为顶层组件时为null
                this.parentSub = props[subscriptionKey] || context[subscriptionKey]

                this.setWrappedInstance = this.setWrappedInstance.bind(this)

                invariant(this.store,
                    `Could not find "${storeKey}" in either the context or ` +
                    `props of "${displayName}". ` +
                    `Either wrap the root component in a <Provider>, ` +
                    `or explicitly pass "${storeKey}" as a prop to "${displayName}".`
                )

                // getState引用当前组件相应Redux的store.getState
                this.getState = this.store.getState.bind(this.store);

                // 构建this.selector属性,其中props方法获取当前的props,run方法更新props(引用对象形式)
                this.initSelector()

                // 构建this.subscription回调函数队列,构建subscription.onStateChange方法,但不挂载
                // componentDidMount方法中,顶层组件redux.store回调队列中挂载父子组件的onStateChange方法
                // redux.store.dispatch方法执行时,触发父子组件的onStateChange方法
                //    更新嵌套组件的props,同时按shouldComponentUpdate条件触发组件重绘
                this.initSubscription()
            }

            // 将subscription回调队列属性传递给子组件,或者将祖先组件的subscription传递给子组件
            getChildContext() {
                return { [subscriptionKey]: this.subscription || this.parentSub }
            }

            // 挂载父子组件的onStateChange方法,绑定dispatch方法触发时更新组件的props属性以及重绘组件
            // connect方法执行过程中,由redux.store.state初始化数据更新组件props组件属性
            componentDidMount() {
                if (!shouldHandleStateChanges) return

                // 顶层组件redux.store、this.subscrption回调队列中挂载父子组件的onStateChange方法
                this.subscription.trySubscribe()
                // connect(mapStateToProps,mapDispatchToProps)方法执行时
                // redux.store.state初始化绑定到react组件props属性过程中,是否更新组件props属性
                // 以及重绘组件,默认不重绘???
                this.selector.run(this.props)
                if (this.selector.shouldComponentUpdate) this.forceUpdate()
            }

            // 由组件更新后、重绘前的props,触发redux.store.dispatch方法更新props,用于重绘
            componentWillReceiveProps(nextProps) {
                this.selector.run(nextProps)
            }

            // 判断组件是否已由redux机制进行重绘
            shouldComponentUpdate() {
                return this.selector.shouldComponentUpdate
            }

            // 组件取消挂载时释放内存,即connect(mapStateToProps,mapDispatchToProps)(component)中component
            componentWillUnmount() {
                if (this.subscription) this.subscription.tryUnsubscribe()

                this.subscription = null
                this.store = null
                this.parentSub = null
                this.selector.run = () => {}
            }

            // 获取被包裹的UI组件
            getWrappedInstance() {
                invariant(withRef,
                  `To access the wrapped instance, you need to specify ` +
                  `{ withRef: true } in the options argument of the ${methodName}() call.`
                )
                return this.wrappedInstance
            }

            setWrappedInstance(ref) {
                this.wrappedInstance = ref
            }

            // 构建this.selector属性,其中props方法获取当前的props,run方法更新props
            // 通过redux.store.state更新、redux.store.dispatch方法触发获取最新的props
            initSelector() {
                const { dispatch } = this.store
                const { getState } = this;
                // 返回react.props计算函数,返回函数在redux.store.dispatch派发action事件时执行
                const sourceSelector = selectorFactory(dispatch, selectorFactoryOptions)

                const selector = this.selector = {
                    shouldComponentUpdate: true,
                    props: sourceSelector(getState(), this.props),// 重新计算react.props
                    run: function runComponentSelector(props) {
                        try {
                            const nextProps = sourceSelector(getState(), props)
                            if (selector.error || nextProps !== selector.props) {
                                selector.shouldComponentUpdate = true
                                selector.props = nextProps
                                selector.error = null
                            }
                        } catch (error) {
                            selector.shouldComponentUpdate = true
                            selector.error = error
                        }
                    }
                }
            }

            // 构建this.subscription回调函数队列,构建subscription.onStateChange方法,但不挂载
            // 顶层组件subscription回调函数队列的onStateChange方法由本组件Redux.store.dispatch触发执行
            // 子组件的onStateChange方法由顶层组件Redux.store.dispatch触发顶层组件相应的onStateChange方法
            //      最终通过调用顶层组件subscription.notifyNestedSubs方法触发执行
            // onStateChange方法用于更新嵌套组件的props,同时按shouldComponentUpdate条件触发组件重绘
            initSubscription() {
                if (shouldHandleStateChanges) {
                    const subscription = this.subscription = new Subscription(this.store, this.parentSub)
                    const dummyState = {}

                    // 在Subsciption模块中,通过redux.store.dispatch方法触发父子组件的this.subscription.onStateChange
                    // 更新嵌套组件的props,同时按shouldComponentUpdate条件触发组件重绘
                    subscription.onStateChange = function onStateChange() {
                        // 更新组件的props
                        this.selector.run(this.props)

                        // this.selector.shouldComponentUpdate为真值重绘当前组件,否则更新子组件的props、按条件重绘子组件
                        if (!this.selector.shouldComponentUpdate) {
                            subscription.notifyNestedSubs()
                        } else {
                            // 更新组件完成后执行回调,
                            this.componentDidUpdate = function componentDidUpdate() {
                                this.componentDidUpdate = undefined
                                subscription.notifyNestedSubs()
                            }

                            // 调用setState更新react组件,setState方法不论prevState、currentState改变与否
                            // 都会比较组件的props进行重绘???
                            this.setState(dummyState)
                        }
                    }.bind(this)
                }
            }

            // 判断顶层组件的store及subscription回调函数队列是否挂载父子组件的onStateChange方法
            isSubscribed() {
                return Boolean(this.subscription) && this.subscription.isSubscribed()
            }

            // 通过selector.props添加额外的属性,当组件更新时,又会发生怎样的情况???
            addExtraProps(props) {
                if (!withRef && !renderCountProp) return props
                // make a shallow copy so that fields added don't leak to the original selector.
                // this is especially important for 'ref' since that's a reference back to the component
                // instance. a singleton memoized selector would then be holding a reference to the
                // instance, preventing the instance from being garbage collected, and that would be bad
                const withExtras = { ...props }
                if (withRef) withExtras.ref = this.setWrappedInstance
                if (renderCountProp) withExtras[renderCountProp] = this.renderCount++
                return withExtras
            }

            render() {
                const selector = this.selector
                // 初始化渲染时,以redux更新props后,不予的重绘???
                selector.shouldComponentUpdate = false

                if (selector.error) {
                    throw selector.error
                } else {
                    return createElement(WrappedComponent, this.addExtraProps(selector.props))
                }
            }
        }

        Connect.WrappedComponent = WrappedComponent
        Connect.displayName = displayName
        Connect.childContextTypes = childContextTypes
        Connect.contextTypes = contextTypes
        Connect.propTypes = contextTypes

        // 开发环境,保证props可由redux机制顺利更新,并完成组件重绘
        if (process.env.NODE_ENV !== 'production') {
            Connect.prototype.componentWillUpdate = function componentWillUpdate() {
                if (this.version !== version) {
                    this.version = version
                    this.initSelector()

                    if (this.subscription) this.subscription.tryUnsubscribe()
                    this.initSubscription()
                    if (shouldHandleStateChanges) this.subscription.trySubscribe()
                }
            }
        }

        return hoistStatics(Connect, WrappedComponent)
    }
}

mapStateToProps.js、mapDispatchToProps.js、wrapMapToProps.js、mergeProps.js

// mapStateToProps.js
import { wrapMapToPropsConstant, wrapMapToPropsFunc } from './wrapMapToProps'

// 当用户配置的mapStateToProps是函数时,使用wrapMapToPropsFunc装饰mapStateToProps
//    传入redux的dispatch方法、react组件的displayName
export function whenMapStateToPropsIsFunction(mapStateToProps) {
	return (typeof mapStateToProps === 'function')
		? wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
		: undefined
}

// 当用户配置的mapStateToProps不是函数时,设置默认的mapStateToProps为空函数;否则不设置
export function whenMapStateToPropsIsMissing(mapStateToProps) {
  	return (!mapStateToProps)
	    ? wrapMapToPropsConstant(() => ({}))
	    : undefined
}

// 当用户配置的mapStateToProps是函数时,使用wrapMapToPropsFunc装饰mapStateToProps
//    传入redux的dispatch方法、react组件的displayName
// 当用户配置的mapStateToProps不是函数时,设置默认的mergeProps为空函数;否则不设置
// 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
// 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性
export default [
	whenMapStateToPropsIsFunction,
	whenMapStateToPropsIsMissing
]



// mapDispatchToProps.js
import { bindActionCreators } from 'redux'
import { wrapMapToPropsConstant, wrapMapToPropsFunc } from './wrapMapToProps'

// 当用户配置的mapDispatchToProps是函数时,使用wrapMapToPropsFunc装饰mapDispatchToProps
//    传入redux的dispatch方法、react组件的displayName
export function whenMapDispatchToPropsIsFunction(mapDispatchToProps) {
    return (typeof mapDispatchToProps === 'function')
        ? wrapMapToPropsFunc(mapDispatchToProps, 'mapDispatchToProps')
        : undefined
}

// 当用户配置的mapDispatchToProps不是函数时,设置默认的mapDispatchToProps为输出redux.store.dispatch方法;否则不设置
export function whenMapDispatchToPropsIsMissing(mapDispatchToProps) {
    return (!mapDispatchToProps)
        ? wrapMapToPropsConstant(dispatch => ({ dispatch }))
        : undefined
}

// 当用户配置的mapDispatchToProps是对象时,调用bindActionCreators生成特定派发方法;否则返回undefined
export function whenMapDispatchToPropsIsObject(mapDispatchToProps) {
    return (mapDispatchToProps && typeof mapDispatchToProps === 'object')
        ? wrapMapToPropsConstant(dispatch => bindActionCreators(mapDispatchToProps, dispatch))
        : undefined
}

// 当用户配置的mapDispatchToProps是函数时,使用wrapMapToPropsFunc装饰mapDispatchToProps
//    传入redux的dispatch方法、react组件的displayName
// 当用户配置的mapDispatchToProps不是函数时,设置默认的mapDispatchToProps为输出redux.store.dispatch方法;否则不设置
// 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
// 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性
export default [
    whenMapDispatchToPropsIsFunction,
    whenMapDispatchToPropsIsMissing,
    whenMapDispatchToPropsIsObject
]



// wrapMapToProps.js
// 普通对象校验
import verifyPlainObject from '../utils/verifyPlainObject'

// 当用户配置的mapDispatchToProps为对象形式时,在mapDispatchToProps模块的whenMapDispatchToPropsIsObject函数中调用
// 参数getConstant为dispatch => bindActionCreators(mapDispatchToProps, dispatch)函数
//      接受dispatch作为参数,生成特定派发action的方法,对象形式,最终挂载给react组件的props属性
//      即调用props.actionname派发特定的action
// 返回函数形式;同用户配置的mapDispatchToProps为函数时统一接口,为函数时需要接受dispatch方法作为参数
//      函数返回值为对象形式,用于更新react组件的props属性
export function wrapMapToPropsConstant(getConstant) {
    return function initConstantSelector(dispatch, options) {
        const constant = getConstant(dispatch, options)

        function constantSelector() { return constant }
        // react-redux自动派发action时,不需要根据react原有的props去判断派发何种action
        constantSelector.dependsOnOwnProps = false 
        return constantSelector
    }
}

// 通过redux的state、dispatch更新react组件的props时,是否需要原有的props作为参数,就此形成新的props
// 用户配置的mapStateToProps、mapDispatchToProps为函数,可添加dependsOnOwnProps属性
// 当其为真值时,意味通过redux的state、dispatch更新react组件的props时,需要原有的props作为参数 
export function getDependsOnOwnProps(mapToProps) {
    return (mapToProps.dependsOnOwnProps !== null && mapToProps.dependsOnOwnProps !== undefined)
        ? Boolean(mapToProps.dependsOnOwnProps)
        : mapToProps.length !== 1
}

// 当用户配置的mapStateToProps(即mapStateToProps、mapDispatchToProps)为函数形式时   
// 参数methodName校验提示用,由connect模块通过match方法调用mapStateToProps或mapDispatchToProps模块传入
//    在connect模块中构建initProxySelector函数
//    initProxySelector在sconnectAdvanced模块中接受redux.dispatch、react.displayName作为参数
//        返回mapToPropsProxy封装函数
//    mapToPropsProxy在selectorFactory模块中接受redux.state|dispatch、react.displayName作为参数
//        正式用户配置的mapStateToProps或mapDispatchToProps函数,更新react.props
export function wrapMapToPropsFunc(mapToProps, methodName) {
    // selectorFactory模块中调用,返回值赋给mapStateToProps或mapDispatchToProps
    // 参数dispatch为容器store的dispatch方法,displayName为容器的displayName
    return function initProxySelector(dispatch, { displayName }) {

        const proxy = function mapToPropsProxy(stateOrDispatch, ownProps) {
            return proxy.dependsOnOwnProps
                ? proxy.mapToProps(stateOrDispatch, ownProps)
                : proxy.mapToProps(stateOrDispatch)
        }

        // 判断通过redux的state、dispatch更新react组件的props时,是否需要原有的props作为参数,就此形成新的props
        proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps)

        // 参数stateOrDispatch、ownProps在selectorFactory模块中传入
        //      针对mapStateToProps传入state,针对mapDispatchToProps传入dispatch
        // 通过proxy.mapToProps方法执行过程中按条件重写proxy.mapToProps,构成递归调用proxy.mapToProps
        // 第一次调用proxy.mapToProps,动态传入react组件原有的props
        // 第二次调用proxy.mapToProps,执行用户配置的mapStateToProps、mapDispatchToProps更新props
        // 第三次调用proxy.mapToProps,当mapDispatchToProps返回执行redux.store.dispatch的函数时
        //      通过递归调用更新props
        proxy.mapToProps = function detectFactoryAndVerify(stateOrDispatch, ownProps) {
            // 重新设定proxy.mapToProps为用户传入的mapToProps函数(即mapStateToProps、mapDispatchToProps)
            // 当再次调用proxy函数时将获取mapToProps返回对象并执行
            proxy.mapToProps = mapToProps
            let props = proxy(stateOrDispatch, ownProps)

            // 用户传入的mapToProps函数(即mapStateToProps、mapDispatchToProps)返回函数
            // 通常是mapDispatchToProps,需要通过执行redux.store.dispatch更新props
            // 再次调用proxy获取该函数的返回对象
            if (typeof props === 'function') {
                proxy.mapToProps = props
                proxy.dependsOnOwnProps = getDependsOnOwnProps(props)
                props = proxy(stateOrDispatch, ownProps)
            }

            // 校验props为普通对象
            if (process.env.NODE_ENV !== 'production') verifyPlainObject(props, displayName, methodName)

            // 用户传入的mapToProps函数返回值,对象形式
            // 即connect接口接受的mapStateToProps或mapDispatchToProps参数函数返回值
            return props
        }

        return proxy
    }
}



// mergeProps.js
// 普通对象校验
import verifyPlainObject from '../utils/verifyPlainObject'

// 默认的mergeProps,原样输出stateProps, dispatchProps, ownProps
export function defaultMergeProps(stateProps, dispatchProps, ownProps) {
    return { ...ownProps, ...stateProps, ...dispatchProps }
}

// 装饰用户配置的mergeProps,传入redux的dispatch方法、react组件的displayName、pure、areMergedPropsEqual
export function wrapMergePropsFunc(mergeProps) {
    // 将redux的dispatch方法、react组件的displayName、pure、areMergedPropsEqual等属性传入mergeProps
    // 用于警告提示或者mergeProps方法中使用,mergeProps中可直接使用dispatch方法
    return function initMergePropsProxy(
        dispatch, { displayName, pure, areMergedPropsEqual }
    ) {
        let hasRunOnce = false
        let mergedProps// 缓存前一次混合mergedProps

        return function mergePropsProxy(stateProps, dispatchProps, ownProps) {
            // mergeProps(stateProps, dispatchProps, ownProps)
            //    将mapStateToProps获得的stateProps、mapDispatchToProps获得的dispatchProps、
            //    以及react组件原有的ownProps,混合为新的props
            const nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps)

            // redux.dispatch事件触发时,傻瓜式重新计算混合props或优化计算props
            if (hasRunOnce) {
                if (!pure || !areMergedPropsEqual(nextMergedProps, mergedProps))
                    mergedProps = nextMergedProps

            // react和redux初始化关联时,返回初次计算生成的nextMergedProps
            } else {
                hasRunOnce = true
                mergedProps = nextMergedProps

                // 校验mergedProps为普通对象
                if (process.env.NODE_ENV !== 'production')
                  verifyPlainObject(mergedProps, displayName, 'mergeProps')
            }

            return mergedProps
        }
    }
}

// 当用户配置的mergeProps是函数时,使用wrapMergePropsFunc装饰mergeProps
//    传入redux的dispatch方法、react组件的displayName、pure、areMergedPropsEqual
// 当用户配置的mergeProps不是函数时,返回undefined
export function whenMergePropsIsFunction(mergeProps) {
    return (typeof mergeProps === 'function')
        ? wrapMergePropsFunc(mergeProps)
        : undefined
}

// 当用户配置的mergeProps不是函数时,设置默认的mergeProps为defaultMergeProps;否则不设置
export function whenMergePropsIsOmitted(mergeProps) {
    return (!mergeProps)
        ? () => defaultMergeProps
        : undefined
}

// 当用户配置的mergeProps是函数时,使用wrapMergePropsFunc装饰mergeProps
//    传入redux的dispatch方法、react组件的displayName、pure、areMergedPropsEqual
// 当用户配置的mergeProps不是函数时,设置默认的mergeProps为defaultMergeProps
// 接受待装饰函数,返回装饰函数构造器,执行后装饰函数
// 数组项在connect模块的match函数中挨个调用,输出为真值时即返回,增加编码的灵活性
export default [
    whenMergePropsIsFunction,
    whenMergePropsIsOmitted
]

selectorFactory.js、verifySubselectors.js

// selectorFactory.js
// 开发环境校验最终装饰函数mapStateToProps、mapDispatchToProps、mergeProps为真值
// 提示最终装饰函数mapStateToProps、mapDispatchToProps不需要react组件原有props传参
import verifySubselectors from './verifySubselectors'
  
// redux.dispatch派发action事件触发时,傻瓜式重新计算react.props
export function impureFinalPropsSelectorFactory(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    dispatch
) {
    return function impureFinalPropsSelector(state, ownProps) {
        return mergeProps(
            mapStateToProps(state, ownProps),
            mapDispatchToProps(dispatch, ownProps),
            ownProps
        )
    }
}

// 定义最终装饰函数mapStateToProps、mapDispatchToProps、mergeProps的执行机制
// 按条件分为初始化执行,调用handleFirstCall函数;再次执行,调用pureFinalPropsSelector
//    并传入redux相关的state、dispatch属性,react相关的ownProps属性
//    返回函数,用于重新获取react组件的props
// 与impureFinalPropsSelectorFactory的差别时
//    impureFinalPropsSelectorFactory每次触发redux.dispatch,均重新计算react.props
//    pureFinalPropsSelectorFactory是优化计算方案,state、props改变时才重新计算
export function pureFinalPropsSelectorFactory(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    dispatch,
    { areStatesEqual, areOwnPropsEqual, areStatePropsEqual }
) {
    let hasRunAtLeastOnce = false// redux.store同react.props是否关联过一次标识
    let state// 缓存上一次redux.store.state
    let ownProps// 缓存上一次react.props
    let stateProps// 缓存上一次redux.store.state赋值给react.props的属性
    let dispatchProps// 缓存上一次redux.store.dispatch构造的特定派发action方法赋值给react.props的属性
    let mergedProps// 缓存stateProps、dispatchProps、ownProps复合集,react组件待更新的props

    // 初始化将redux.store.state、redux.store.dispatch按条件赋值给react.props
    function handleFirstCall(firstState, firstOwnProps) {
        state = firstState
        ownProps = firstOwnProps

        // 将redux.store.state赋值给react.props,特定情况下需要react组件原有的props设定赋值情况
        stateProps = mapStateToProps(state, ownProps)

        // 将redux.store.dispatch构造的特定派发action方法赋值给react.props
        // 特定情况下需要react组件原有的props设定赋值情况
        dispatchProps = mapDispatchToProps(dispatch, ownProps)

        // 混合stateProps、dispatchProps赋值给react.props,特定情况下需要react组件原有的props设定赋值情况
        mergedProps = mergeProps(stateProps, dispatchProps, ownProps)

        hasRunAtLeastOnce = true
        return mergedProps
    }

    // redux的dispatch触发且react组件props改变时,重新获取redux.store.state、redux.store.dispatch相应属性
    // 按条件赋值给react.props
    function handleNewPropsAndNewState() {
        // 因redux的dispatch触发、react组件props改变,重新将redux.store.state绑定在react.props属性上
        stateProps = mapStateToProps(state, ownProps)

        // 因react.props变动,重新将redux.dispatch特定的派发方法绑定在react.props属性上
        if (mapDispatchToProps.dependsOnOwnProps)
            dispatchProps = mapDispatchToProps(dispatch, ownProps)

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

    // react组件props改变时,重新获取redux.store.state、redux.store.dispatch相应属性,按条件赋值给react.props
    function handleNewProps() {
        if (mapStateToProps.dependsOnOwnProps)
            stateProps = mapStateToProps(state, ownProps)

        // 因react.props变动,重新将redux.dispatch特定的派发方法绑定在react.props属性上
        if (mapDispatchToProps.dependsOnOwnProps)
            dispatchProps = mapDispatchToProps(dispatch, ownProps)

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

    // redux的dispatch触发,引起state改变时,重新获取redux.store.state,按条件赋值给react.props
    // redux机制,dispatch(action)触发事件后,state在回调函数执行前已改变
    function handleNewState() {
        const nextStateProps = mapStateToProps(state, ownProps)
        const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps)
        stateProps = nextStateProps
        
        if (statePropsChanged)
            mergedProps = mergeProps(stateProps, dispatchProps, ownProps)

        return mergedProps
    }
    
    // redux.dispatch事件触发时,重新将redux.store.state、redux.store.dispatch按条件赋值给react.props
    // react.props改变需要在redux.dispatch事件触发过程中发生
    function handleSubsequentCalls(nextState, nextOwnProps) {
        // 默认判断react.props是否修改,需要重新将redux.state、redux.dispatch按条件赋值给react.props
        // 用户重写判断机制,可以实现修改react.props部分属性时,避过react-redux通过redux.store重新计算props
        const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps)
        
        // 默认判断redux.state是否修改,需要重新将redux.state、redux.dispatch按条件赋值给react.props
        // 用户重写判断机制,可以实现修改redux.state部分属性时,避过react-redux通过redux.store重新计算props
        const stateChanged = !areStatesEqual(nextState, state)

        state = nextState
        ownProps = nextOwnProps

        // redux的dispatch触发且react组件props改变时,重新获取redux.store.state、redux.store.dispatch相应属性
        // 按条件赋值给react.props
        if (propsChanged && stateChanged) return handleNewPropsAndNewState()

        // react组件props改变时,重新获取redux.store.state、redux.store.dispatch相应属性,按条件赋值给react.props
        if (propsChanged) return handleNewProps()

        // redux的dispatch触发,引起state改变时,重新获取redux.store.state,按条件赋值给react.props
        if (stateChanged) return handleNewState()

        // redux的dispatch未曾触发且react组件props未曾改变,直接返回前一次props
        return mergedProps
    }

    // 返回函数,优点是可以使用闭包变量缓存前次的state及ownProps
    // 定义最终装饰函数mapStateToProps、mapDispatchToProps、mergeProps的执行机制
    // 传入redux相关的state、dispatch属性,react相关的ownProps属性
    return function pureFinalPropsSelector(nextState, nextOwnProps) {
        return hasRunAtLeastOnce
            ? handleSubsequentCalls(nextState, nextOwnProps)
            : handleFirstCall(nextState, nextOwnProps)
    }
}

// connectAdvanced模块中调用,通过connect模块传入,返回react.props计算函数
// 参数dispatch为redux.store的dispatch方法,次参对象为react组件的属性
//    各参数传给装饰函数initMapStateToProps、initMapDispatchToProps、initMergeProps
//    获取mapStateToProps、mapDispatchToProps、mergeProps计算react组件待变更的props
export default function finalPropsSelectorFactory(dispatch, {
    initMapStateToProps,
    initMapDispatchToProps,
    initMergeProps,
    ...options
}) {
    // 获取最终装饰函数mapStateToProps、mapDispatchToProps、mergeProps,用以计算计算react组件待变更的props
    const mapStateToProps = initMapStateToProps(dispatch, options)
    const mapDispatchToProps = initMapDispatchToProps(dispatch, options)
    const mergeProps = initMergeProps(dispatch, options)

    // 开发环境校验最终装饰函数mapStateToProps、mapDispatchToProps、mergeProps为真值
    // 提示最终装饰函数mapStateToProps、mapDispatchToProps不需要react组件原有props传参
    if (process.env.NODE_ENV !== 'production') {
        verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps, options.displayName)
    }

    // options.pure在connect模块中设置默认为真值
    const selectorFactory = options.pure
        ? pureFinalPropsSelectorFactory// 傻瓜式计算react.props
        : impureFinalPropsSelectorFactory// 优化计算react.props

    // 定义最终装饰函数mapStateToProps、mapDispatchToProps、mergeProps调用机制,并传入dispatch、options参数
    // 返回react.props计算函数
    return selectorFactory(
        mapStateToProps,
        mapDispatchToProps,
        mergeProps,
        dispatch,
        options
    )
}



// verifySubselectors.js
import warning from '../utils/warning'

function verify(selector, methodName, displayName) {
    // 校验最终装饰函数mapStateToProps、mapDispatchToProps、mergeProps为真值
    if (!selector) {
        throw new Error(`Unexpected value for ${methodName} in ${displayName}.`)

    // 提示最终装饰函数mapStateToProps、mapDispatchToProps不需要react组件原有props传参
    } else if (methodName === 'mapStateToProps' || methodName === 'mapDispatchToProps') {
        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)
}

Subscription.js

const CLEARED = null
const nullListeners = { notify() {} }

// 类似jquery的Callbacks回调函数队列,用于向队列next中添加和移除回调函数,以及触发回调函数的执行
function createListenerCollection() {
    let current = []
    let next = []

    return {
        clear() {
            next = CLEARED
            current = CLEARED
        },

        notify() {
            const listeners = current = next
            for (let i = 0; i < listeners.length; i++) {
                listeners[i]()
            }
        },

        subscribe(listener) {
            let isSubscribed = true
            if (next === current) next = current.slice()
            next.push(listener)

            return function unsubscribe() {
                if (!isSubscribed || current === CLEARED) return
                isSubscribed = false

                if (next === current) next = current.slice()
                next.splice(next.indexOf(listener), 1)
            }
        }
    }
}

// 通过向react组件挂载this.subscription对象
// 将当前组件及其子孙组件的subscription.onStateChange绑定为redux.stroe.dispatch方法的回调
// subscription.onStateChange方法中,调用this.selector.run重新计算props
// 本层组件的onStateChange方法通过redux.store.subscribe绑定为回调函数
//     同时本层组件的onStateChange触发this.subscription.notifyNestedSubs方法
//     而子组件的onStateChange通过this.subscription.addNestedSub绑定为回调函数
// 这样redux.store.dispatch就可以触发父子组件的props更新
export default class Subscription {
    constructor(store, parentSub) {
        this.store = store
        this.parentSub = parentSub
        this.unsubscribe = null
        this.listeners = nullListeners
    }

    // 添加回调函数,默认内部subscription方法使用
    // 向父组件的subscription回调函数队列添加子组件subscription对象的onStateChange方法
    addNestedSub(listener) {
        this.trySubscribe()
        return this.listeners.subscribe(listener)
    }

    // 触发回调函数执行,默认connectAdvanced模块构建的onStateChange方法内使用
    // 父组件的subscription回调函数队列触发子组件subscription对象的onStateChange方法
    notifyNestedSubs() {
        this.listeners.notify()
    }

    // 顶层组件的store及subscription回调函数队列是否挂载父子组件的onStateChange方法
    isSubscribed() {
        return Boolean(this.unsubscribe)
    }

    // 挂载this.onStateChange方法,用于重新获得props,触发this.setState更新组件
    // 当前组件为顶层组件,this.store挂载this.onStateChange方法
    // 当前组件为子组件,通过父组件的onStateChange调用subscription.notifyNestedSubs挂载this.onStateChange方法
    trySubscribe() {
        if (!this.unsubscribe) {
            // this.onStateChange is set by connectAdvanced.initSubscription()
            // 当前组件为顶层组件时,通过this.store.subscribe挂载this.onStateChange方法
            //    即通过this.store.dispatch方法触发state改变的同时,同时触发this.onStateChange方法
            // 当前组件为子组件时,通过父组件的onStateChange调用subscription.notifyNestedSubs
            //    触发子组件的onStateChange方法
            // 怎样更新组件???
            this.unsubscribe = this.parentSub
              ? this.parentSub.addNestedSub(this.onStateChange)
              : this.store.subscribe(this.onStateChange)
       
            this.listeners = createListenerCollection()
        }
    }

    tryUnsubscribe() {
        if (this.unsubscribe) {
            this.unsubscribe()
            this.unsubscribe = null
            this.listeners.clear()
            this.listeners = nullListeners
        }
    }
}

shallowEqual.js、verifyPlainObject.js、warning.js、storeShape.js

// shallowEqual.js、verifyPlainObject.js、warning.js、storeShape.js
const hasOwn = Object.prototype.hasOwnProperty

// 比较变量是否全等,或者普通对象单层比较是否相同
export default function shallowEqual(a, b) {
    if (a === b) return true

    let countA = 0
    let countB = 0
    
    for (let key in a) {
        if (hasOwn.call(a, key) && a[key] !== b[key]) return false
        countA++
    }

    for (let key in b) {
        if (hasOwn.call(b, key)) countB++
    }

    return countA === countB
}



// verifyPlainObject.js
import isPlainObject from 'lodash/isPlainObject'
import warning from './warning'

// 校验value是否普通对象
export default function verifyPlainObject(value, displayName, methodName) {
	if (!isPlainObject(value)) {
		warning(
		  	`${methodName}() in ${displayName} must return a plain object. Instead received ${value}.`
		)
	}
}



// warning.js
// 打印错误或报错
export default function warning(message) {
    /* eslint-disable no-console */
    if (typeof console !== 'undefined' && typeof console.error === 'function') {
        console.error(message)
    }
    /* eslint-enable no-console */
    try {
        throw new Error(message)
        /* eslint-disable no-empty */
    } catch (e) {}
    /* eslint-enable no-empty */
}



// storeShape.js
import { PropTypes } from 'react'

export default PropTypes.shape({
  	subscribe: PropTypes.func.isRequired,
  	dispatch: PropTypes.func.isRequired,
  	getState: PropTypes.func.isRequired
})

猜你喜欢

转载自schifred.iteye.com/blog/2348354