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,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,methodName)
- // 用户传入的mapToProps函数返回值,对象形式
- // 即connect接口接受的mapStateToProps或mapDispatchToProps参数函数返回值
- return props
- }
- return proxy
- }
- }
- // mergeProps.js
- // 普通对象校验
- import verifyPlainObject from '../utils/verifyPlainObject'
- // 默认的mergeProps,原样输出stateProps,dispatchProps,ownProps
- export function defaultMergeProps(stateProps,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,areMergedPropsEqual }
- ) {
- let hasRunOnce = false
- let mergedProps// 缓存前一次混合mergedProps
- return function mergePropsProxy(stateProps,ownProps) {
- // mergeProps(stateProps,ownProps)
- // 将mapStateToProps获得的stateProps、mapDispatchToProps获得的dispatchProps、
- // 以及react组件原有的ownProps,混合为新的props
- const nextMergedProps = mergeProps(stateProps,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,'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,dispatch
- ) {
- return function impureFinalPropsSelector(state,ownProps) {
- return mergeProps(
- mapStateToProps(state,ownProps),mapDispatchToProps(dispatch,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,dispatch,{ areStatesEqual,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,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,ownProps)
- return mergedProps
- }
- // react组件props改变时,重新获取redux.store.state、redux.store.dispatch相应属性,按条件赋值给react.props
- function handleNewProps() {
- if (mapStateToProps.dependsOnOwnProps)
- stateProps = mapStateToProps(state,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,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,...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,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,options
- )
- }
- // verifySubselectors.js
- import warning from '../utils/warning'
- function verify(selector,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,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,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
- })