###react-redux源码结构
-- index.js
-- utils - shallowEqual.js - storeShape.js - warning.js - wrapActionCreators.js
--components - Provider.js - connect.js
为了方便解读,先从基础方法开始
index.js 源码
import Provider from './components/Provider' // 导入Provider组件 import connect from './components/connect' // 导入connect组件 export { Provider,connect } // 将Provider,connect导出
utils 工具包源码
warning.js
/** * * 在console打印一条警告信息 * * @param {String} 警告信息内容 * @returns {void} 返回值 */ export default function warning(message) { // 文件中指定规则(console)不验证 /* 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 */ }
shallowEqual.js
// 判断objA 与 obj 是否相等 export default function shallowEqual(objA,objB) { // 如果objA和objB是严格相等,结果相等 if (objA === objB) { return true } // 获取 objA 和 objB 的所有属性 const keysA = Object.keys(objA) const keysB = Object.keys(objB) // 属性长度不相等,结果不相等 if (keysA.length !== keysB.length) { return false } // 使用hasWon引用Object.prototype.hasOwnProperty方法 const hasOwn = Object.prototype.hasOwnProperty // objB 中不含有 objA 中的属性,结果不相等 for (let i = 0; i < keysA.length; i++) { if (!hasOwn.call(objB,keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) { return false } } return true }
storeShape.js
import { PropTypes } from 'react' // 导出store Prop 验证规则 export default PropTypes.shape({ subscribe: PropTypes.func.isrequired,dispatch: PropTypes.func.isrequired,getState: PropTypes.func.isrequired })
wrapActionCreators.js
// 导入 bindActionCreators 方法,此方法在后续redux源码会讲到 import { bindActionCreators } from 'redux' // 将dispatch应用到actionCreators export default function wrapActionCreators(actionCreators) { return dispatch => bindActionCreators(actionCreators,dispatch) }
components源码
Provider.js
// Provider 依赖react,导入react中元素 import { Component,PropTypes,Children } from 'react' // 导入store验证规则以及警告提示方法 import storeShape from '../utils/storeShape' import warning from '../utils/warning' // 标识是否已经收到警告 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是一个内部组建 export default class Provider extends Component { // 构造方法传入props和context constructor(props,context) { super(props,context) this.store = props.store } // 返回从构造方法传递的store,将store传递给子孙component getChildContext() { return { store: this.store } } // 返回仅有的一个子元素,否则(没有子元素或超过一个子元素) // 报错且不渲染任何东西。 这也说明Provider下必须只能是一个 // 子元素 render() { return Children.only(this.props.children) } } // 如果我们运行的环境是production,则还需要定义 // componentWillReceiveProps原型方法 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 }
connect.js react-redux真正的主角上场了,游戏才刚开始,游戏结束还有59分钟。
// 这个就是导入一系列react、utils中的方法 import { Component,createElement } from 'react' import storeShape from '../utils/storeShape' import shallowEqual from '../utils/shallowEqual' import wrapActionCreators from '../utils/wrapActionCreators' import warning from '../utils/warning' import isPlainObject from 'lodash/isPlainObject' import hoistStatics from 'hoist-non-react-statics' import invariant from 'invariant' // 一看default,嘿,connect方法中mapStateToProps、mapDispatchToProps的默认值。 // mapStateToProps默认为一个空对象 // mapDispatchToProps默认为包含一个dispatch方法的对象 // mergeProps主要是合并上两个和其他 const defaultMapStateToProps = state => ({}) // eslint-disable-line no-unused-vars const defaultMapDispatchToProps = dispatch => ({ dispatch }) const defaultMergeProps = (stateProps,dispatchProps,parentProps) => ({ ...parentProps,...stateProps,...dispatchProps }) // 显示组件名称 function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component' } // 运行指定方法并捕获异常,并将错误放在errorObject对象中的value中 let errorObject = { value: null } function tryCatch(fn,ctx) { try { return fn.apply(ctx) } catch (e) { errorObject.value = e return errorObject } } // Helps track hot reloading. let nextVersion = 0 // connect是一个高阶函数,它包含四个参数,并返回一个 // 生产Component的函数,它将真正的Component作为参数传入 export default function connect(mapStateToProps,mapDispatchToProps,mergeProps,options = {}) { // mapStateToProps第一个参数(function) // 返回bool值,使用传入mapStateToProps判断是否可订阅 const shouldSubscribe = Boolean(mapStateToProps) //mapStateToProps默认值,即{} const mapState = mapStateToProps || defaultMapStateToProps let mapDispatch // mapDispatchToProps为第二个参数(function | object), // mapDispatchToProps可传递的类型为function 或许 对象 // 如果传递的类型为function if (typeof mapDispatchToProps === 'function') { mapDispatch = mapDispatchToProps // 如果没有传递mapDispatchToProps,则为默认 } else if (!mapDispatchToProps) { mapDispatch = defaultMapDispatchToProps } else { // 只要敢调用wrapActionCreators,它就返回参数含有dispatch的方法。 // wrapActionCreators方法中应用了bindActionCreators mapDispatch = wrapActionCreators(mapDispatchToProps) } // 第三个参数(function), 如果指定这个参数 // mapStateToProps() 与 mapDispatchToProps()的 // 执行结果和组件自身的 props 将传入到这个回调函数中 const finalMergeProps = mergeProps || defaultMergeProps // 第四个参数(Object) // pure为true表示执行shouldComponentUpdate并且浅比较mergeProps // withRef为true表示connector会保存一个对被包装组件实例的引用, // 该引用通过 getWrappedInstance() 方法获得 const { pure = true,withRef = false } = options // 判断是否检查 mergeProps const checkMergedEquals = pure && finalMergeProps !== defaultMergeProps // 保持版本号增长(非生产环境下). const version = nextVersion++ // connect的返回值,WrappedComponent是React中的一个容器组件 return function wrapWithConnect(WrappedComponent) { // 格式化顶级组件的名称 const connectDisplayName = `Connect(${getDisplayName(WrappedComponent)})` // 校验State中的props 是否为纯对象 function checkStateShape(props,methodName) { // 判断对象否为纯粹的对象字面量,即用来检测一个对象是否由{}或new Object()创建 if (!isPlainObject(props)) { warning( `${methodName}() in ${connectDisplayName} must return a plain object. ` + `Instead received ${props}.` ) } } // 合并stateProps、dispatchProps、parentProps function computeMergedProps(stateProps,parentProps) { const mergedProps = finalMergeProps(stateProps,parentProps) // 不为生产环境时才执行 if (process.env.NODE_ENV !== 'production') { checkStateShape(mergedProps,'mergeProps') } return mergedProps } // 定义Connect组件 class Connect extends Component { // 在接收到新的 props 或者 state,将要渲染之前调用。 // 该方法在初始化渲染的时候不会调用 // 如果 shouldComponentUpdate 返回 false,则 render() 将不会执行 shouldComponentUpdate() { return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged } // 构造方法 constructor(props,context) { super(props,context) this.version = version //从祖先Component处获得store this.store = props.store || context.store // props 或 context没有存放store,invariant(this.store,`Could not find "store" in either the context or ` + `props of "${connectDisplayName}". ` + `Either wrap the root component in a <Provider>,` + `or explicitly pass "store" as a prop to "${connectDisplayName}".` ) // 从store获取state并成为当前对象的state const storeState = this.store.getState() this.state = { storeState } this.clearCache() } computeStateProps(store,props) { // 如果finalMapStateToProps不存在,表示还没有执行过configureFinalMapState方法 if (!this.finalMapStateToProps) { return this.configureFinalMapState(store,props) } // 获取store中的state, 并执行finalMapStateToProps // 如果StateProps依赖OwnProps,需要传递props const state = store.getState() const stateProps = this.doStatePropsDependOnOwnProps ? this.finalMapStateToProps(state,props) : this.finalMapStateToProps(state) if (process.env.NODE_ENV !== 'production') { checkStateShape(stateProps,'mapStateToProps') } return stateProps } // 1. 调用mapState,即connect第一个参数,返回包含 // 2. 判断是否为 function // 3. 判断ffinalMapStateToProps参数个数,长度为1,代表不依赖ownProps,否则反之 configureFinalMapState(store,props) { const mappedState = mapState(store.getState(),props) const isFactory = typeof mappedState === 'function' this.finalMapStateToProps = isFactory ? mappedState : mapState this.doStatePropsDependOnOwnProps = this.finalMapStateToProps.length !== 1 if (isFactory) { return this.computeStateProps(store,props) } if (process.env.NODE_ENV !== 'production') { checkStateShape(mappedState,'mapStateToProps') } return mappedState } computeDispatchProps(store,props) { // 如果没有调用过configureFinalMapDispatch, 则先调 // 用configureFinalMapDispatch if (!this.finalMapDispatchToProps) { return this.configureFinalMapDispatch(store,props) } // 获取store中的dispatch, 并执行finalMapDispatchToProps,返回值为对象 // 如果DispatchProps依赖OwnProps,需要传递props const { dispatch } = store const dispatchProps = this.doDispatchPropsDependOnOwnProps ? this.finalMapDispatchToProps(dispatch,props) : this.finalMapDispatchToProps(dispatch) if (process.env.NODE_ENV !== 'production') { checkStateShape(dispatchProps,'mapDispatchToProps') } // 返回最终dispatchProps return dispatchProps } configureFinalMapDispatch(store,props) { // 调用mapDispatch()方法, mapDisPatch方法返回一个含有dispatch[也可能含有props]参数的function const mappedDispatch = mapDispatch(store.dispatch,props) // 如果返回的是函数,isFactory为true。 const isFactory = typeof mappedDispatch === 'function' // isFactory为true,返回mappedDispatch,否则返回默认值 this.finalMapDispatchToProps = isFactory ? mappedDispatch : mapDispatch // 判断finalMapDispatchToProps参数个数,长度为1,代表不依赖ownProps,否则反之 this.doDispatchPropsDependOnOwnProps = this.finalMapDispatchToProps.length !== 1 // mappedDispatch === 'function'成立,调用computeDispatchProps if (isFactory) { return this.computeDispatchProps(store,props) } if (process.env.NODE_ENV !== 'production') { checkStateShape(mappedDispatch,'mapDispatchToProps') } return mappedDispatch } // 是否需要更新StateProps updateStatePropsIfNeeded() { const nextStateProps = this.computeStateProps(this.store,this.props) if (this.stateProps && shallowEqual(nextStateProps,this.stateProps)) { return false } this.stateProps = nextStateProps return true } // 是否需要更新DispatchProps updateDispatchPropsIfNeeded() { const nextDispatchProps = this.computeDispatchProps(this.store,this.props) if (this.dispatchProps && shallowEqual(nextDispatchProps,this.dispatchProps)) { return false } this.dispatchProps = nextDispatchProps return true } // 是否需要更新MergeProps updateMergedPropsIfNeeded() { const nextMergedProps = computeMergedProps(this.stateProps,this.dispatchProps,this.props) if (this.mergedProps && checkMergedEquals && shallowEqual(nextMergedProps,this.mergedProps)) { return false } this.mergedProps = nextMergedProps return true } // 是否已经被订阅,订阅返回true isSubscribed() { return typeof this.unsubscribe === 'function' } // 执行订阅,并使用handleChange处理回调 // 先自动调用handleChange一次 trySubscribe() { if (shouldSubscribe && !this.unsubscribe) { this.unsubscribe = this.store.subscribe(this.handleChange.bind(this)) this.handleChange() } } // 取消订阅 tryUnsubscribe() { if (this.unsubscribe) { this.unsubscribe() this.unsubscribe = null } } // 初始化渲染执行之后立刻调用一次 // 渲染之后执行订阅 componentDidMount() { this.trySubscribe() } // 组件接收到新的 props 的时候调用。在初始化渲染的时候,该方法不会调用。 // 判断传递的Props是否与当前props相等 componentWillReceiveProps(nextProps) { if (!pure || !shallowEqual(nextProps,this.props)) { this.haveOwnPropsChanged = true } } // 在组件从 DOM 中移除的时候立刻被调用 // 取消订阅 、清除缓存 componentWillUnmount() { this.tryUnsubscribe() this.clearCache() } // reset变量及引用 clearCache() { this.dispatchProps = null this.stateProps = null this.mergedProps = null this.haveOwnPropsChanged = true this.hasStoreStateChanged = true this.haveStatePropsBeenPrecalculated = false this.statePropsPrecalculationError = null this.renderedElement = null this.finalMapDispatchToProps = null this.finalMapStateToProps = null } // handle回调实现 handleChange() { // 如果被取消订阅,终止执行。 if (!this.unsubscribe) { return } // 比较当前state是否store中的state相同 // 相同停止执行 const storeState = this.store.getState() const prevStoreState = this.state.storeState if (pure && prevStoreState === storeState) { return } if (pure && !this.doStatePropsDependOnOwnProps) { const haveStatePropsChanged = tryCatch(this.updateStatePropsIfNeeded,this) if (!haveStatePropsChanged) { return } if (haveStatePropsChanged === errorObject) { this.statePropsPrecalculationError = errorObject.value } this.haveStatePropsBeenPrecalculated = true } // 重新设置state this.hasStoreStateChanged = true this.setState({ storeState }) } // 获取被包装组件实例的引用 // 如果没有设置withRef为true, // 执行invariant getWrappedInstance() invariant(withRef,`To access the wrapped instance,you need to specify ` + `{ withRef: true } as the fourth argument of the connect() call.` ) return this.refs.wrappedInstance } render() { // 解构所需变量 const { haveOwnPropsChanged,hasStoreStateChanged,haveStatePropsBeenPrecalculated,statePropsPrecalculationError,renderedElement } = this // reset变量 this.haveOwnPropsChanged = false this.hasStoreStateChanged = false this.haveStatePropsBeenPrecalculated = false this.statePropsPrecalculationError = null // 如果有错误存在statePropsPrecalculationError中,抛出错误 if (statePropsPrecalculationError) { throw statePropsPrecalculationError } let shouldUpdateStateProps = true let shouldUpdateDispatchProps = true // 允许浅比较并且renderdElement存在,说明只需刷新 if (pure && renderedElement) { // 判断是否需要更新state shouldUpdateStateProps = hasStoreStateChanged || ( haveOwnPropsChanged && this.doStatePropsDependOnOwnProps ) // 判断是否需要更新dispatch shouldUpdateDispatchProps = haveOwnPropsChanged && this.doDispatchPropsDependOnOwnProps } let haveStatePropsChanged = false let haveDispatchPropsChanged = false if (haveStatePropsBeenPrecalculated) { haveStatePropsChanged = true } else if (shouldUpdateStateProps) { haveStatePropsChanged = this.updateStatePropsIfNeeded() } if (shouldUpdateDispatchProps) { haveDispatchPropsChanged = this.updateDispatchPropsIfNeeded() } let haveMergedPropsChanged = true // 如果haveStatePropsChanged、haveDispatchPropsChanged、 // haveOwnPropsChanged其中一个被改变 if ( haveStatePropsChanged || haveDispatchPropsChanged || haveOwnPropsChanged ) { haveMergedPropsChanged = this.updateMergedPropsIfNeeded() } else { haveMergedPropsChanged = false } if (!haveMergedPropsChanged && renderedElement) { return renderedElement } // 如果withRef为true,则保存一个对被包装组件实例的引用: // ref: 'wrappedInstance' 是此组建创建的引用 if (withRef) { this.renderedElement = createElement(WrappedComponent,{ ...this.mergedProps,ref: 'wrappedInstance' }) } else { this.renderedElement = createElement(WrappedComponent,this.mergedProps ) } return this.renderedElement } } Connect.displayName = connectDisplayName Connect.WrappedComponent = WrappedComponent Connect.contextTypes = { store: storeShape } Connect.propTypes = { store: storeShape } if (process.env.NODE_ENV !== 'production') { Connect.prototype.componentWillUpdate = function componentWillUpdate() { if (this.version === version) { return } // We are hot reloading! this.version = version this.trySubscribe() this.clearCache() } } // 这才是衔接redux 与 react 的关键, 将 WrappedComponent 中 // 除去关键字的所有的key和Symbols赋给 Connect (react 和 js关键字) // [hoist-non-react-statics源码](https://github.com/mridgway/hoist-non-react-statics/blob/master/index.js) return hoistStatics(Connect,WrappedComponent) } }原文链接:https://www.f2er.com/react/306459.html