React Redux: 从文档看源码 - Connect工具类篇(1)
注:这篇文章只是讲解React Redux这一层,并不包含Redux部分。Redux有计划去学习,等以后学习了Redux源码以后再做分析; Connect工具类篇这里讲的其实是connect方法的基础,本来是准备先把connectAdvanced和Provider写完,再专门写connect和相关方法的,但是发现connectAdvanced也用到了很多这些基础方法,所以就停下来,写下面的这些东西。 之前没有上过代码结构图,这里贴张图上来(5.0.1版本) React Redux在最近的几个版本中对代码做了拆分和优化,之前看4.x的代码的时候,connect下面所有的方法都在一个文件里面,而且逻辑也不够清晰。当时本来想吐槽他们的源代码的,但是升级到5.x以后,就发现代码清晰很多,只不过代码逻辑复杂度更上一层楼。。。 dependsOnOwnProps单独提出来这个属性,做一个简单的说明。dependsOnOwnProps属性并不是对外的属性,而是代码内部逻辑使用的,会在多个方法中用到,这个属性主要是针对connect的两个参数mapStateToProps,mapDispatchToProps。 根据文档,mapStateToProps可以是function或者null,mapDispatchToProps可以是function,object或者null。如果是function,当定义的时候,可以选择是否传入ownProps对象,比如 所以dependsOnOwnProps就是当ownProps更新的时候,用来判断是否需要重新调用对应方法获取新的结果。 wrapMapToProps.jsgetDependsOnownProps这段代码主要的作用就是判断map(State/Dispptch)ToProps方法是否需要ownProps。 export function getDependsOnOwnProps(mapToProps) { return (mapToProps.dependsOnOwnProps !== null && mapToProps.dependsOnOwnProps !== undefined) ? Boolean(mapToProps.dependsOnOwnProps) : mapToProps.length !== 1 } 这里通过判断方法的length来进行判断是否需要ownProps,当mapToProps.length !== 1的时候,就是需要。反之,就是不需要。 这里有几种情况:
wrapMapToPropsConstant首先,根据文档mapDispatchToProps是optional的,而且可以是function或者object。 export function wrapMapToPropsConstant(getConstant) { return function initConstantSelector(dispatch,options) { const constant = getConstant(dispatch,options) function constantSelector() { return constant } constantSelector.dependsOnOwnProps = false return constantSelector } } 首先查看一下这个方法的调用,在mapDispatchToProps.js里面有两处调用: export function whenMapDispatchToPropsIsFunction(mapDispatchToProps) {...} export function whenMapDispatchToPropsIsMissing(mapDispatchToProps) { return (!mapDispatchToProps) ? wrapMapToPropsConstant(dispatch => ({ dispatch })) // 会生成(dispatch,options)=>()=>({dispatch}) : undefined } export function whenMapDispatchToPropsIsObject(mapDispatchToProps) { return (mapDispatchToProps && typeof mapDispatchToProps === 'object') ? wrapMapToPropsConstant(dispatch => bindActionCreators(mapDispatchToProps,dispatch)) // 会生成(dispatch,options)=>()=>bindActionCreators(mapDispatchToProps,dispatch),也就是绑定过dispatch的actions : undefined } 在这里,如果mapDispatchToProps为null或者是object的时候,调用wrapMapToPropsConstant方法。 文档中也提到:
注: 在whenMapDispatchToPropsIsObject只是返回(dispatch,options)=>()=>disptachedActions,然后会在selectorFactory里面传入dispatch和options,并根据dependsOnOwnProps调用,最后获得里面的constant。最后会在mergeProps方法里面,把state,constant,props进行合并 wrapMapToPropsFunc这个方法主要是针对mapStateToProps和mapDispatchToProps是function的情况。 mapStateToProps
mapDispatchToProps
两个都有
代码是这样子的: export function wrapMapToPropsFunc(mapToProps,methodName) { return function initProxySelector(dispatch,{ displayName }) { const proxy = function mapToPropsProxy(stateOrDispatch,ownProps) { return proxy.dependsOnOwnProps ? proxy.mapToProps(stateOrDispatch,ownProps) : proxy.mapToProps(stateOrDispatch) } proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps) // 初始化时根据mapToProps来判断是否需要ownProps proxy.mapToProps = function detectFactoryAndVerify(stateOrDispatch,ownProps) { // 第一次调用的时候,会进到这里 proxy.mapToProps = mapToProps let props = proxy(stateOrDispatch,ownProps) // 先获取mapToProps的返回值 if (typeof props === 'function') { // 如果返回值是function,那么符合文档中说的特殊情况 proxy.mapToProps = props // 把这个props当作真正的mapToProps proxy.dependsOnOwnProps = getDependsOnOwnProps(props) // 根据新的props方法来更新是否需要ownProps props = proxy(stateOrDispatch,ownProps) // 获取最终结果 } if (process.env.NODE_ENV !== 'production') verifyPlainObject(props,displayName,methodName) // 如果是非production环境下,判断结果的类型 return props } return proxy } } 这里的mapToProps就是map(State/Dispatch)ToProps的意思,这个代码主要做了几个工作:
注: 从代码里面看出一点,就是当function返回function的情况,其实dependsOnOwnProps并不是根据外层的function来定的,而是根据返回的function而定的。而且,像文档中所说,他的主要作用是做对比(和上一个state,ownProps),所以我猜代码应该像这个样子 function mapStateToProps(state,ownProps){ // ownProps可选 let oldState = state,oldProps = ownProps,lastState; return function(state,ownProps){ // ownProps可选 // 在这里对比当前state,ownProps和之前的oldState,oldProps,来生成新的state,或者直接用之前的state let ret = {}; if(!lastState) { lastState = state; // do some computation here. } else if(!shallowEqual(state,oldState) || !shallowEqual(oldProps,ownProps)) { lastState = state; // do some computation here } oldState = state; oldProps = ownProps; return lastState; } } 同时,真正是否渲染根据ownProps改变,是基于内层的function来定的。所以说: dependsOnOwnProps为false function mapStateToProps(state,ownProps){ return function(state){ } } dependsOnOwnProps为true function mapStateToProps(state){ return function(state,ownProps){ } } mapDispatchToProps.js这个JS中提供了三个方法,分别应对mapDispatchToProps是function,object和null的情况。 whenMapDispatchToPropsIsFunctionexport function whenMapDispatchToPropsIsFunction(mapDispatchToProps) { return (typeof mapDispatchToProps === 'function') ? wrapMapToPropsFunc(mapDispatchToProps,'mapDispatchToProps') : undefined } 当mapDispatchToProps是function的时候,用wrapMapToPropsFunc来进行调用。最后返回的应该是 whenMapDispatchToPropsIsMissingexport function whenMapDispatchToPropsIsMissing(mapDispatchToProps) { return (!mapDispatchToProps) ? wrapMapToPropsConstant(dispatch => ({ dispatch })) : undefined } 当mapDispatchToProps是null的时候,调用 whenMapDispatchToPropsIsObjectexport function whenMapDispatchToPropsIsObject(mapDispatchToProps) { return (mapDispatchToProps && typeof mapDispatchToProps === 'object') ? wrapMapToPropsConstant(dispatch => bindActionCreators(mapDispatchToProps,dispatch)) : undefined } 当mapDispatchToProps是object的时候,调用 最后的export defaultexport default [ whenMapDispatchToPropsIsFunction,whenMapDispatchToPropsIsMissing,whenMapDispatchToPropsIsObject ] 这里写的很有趣,也很值得借鉴。先看一下调用的地方: const initMapDispatchToProps = match(mapDispatchToProps,mapDispatchToPropsFactories,'mapDispatchToProps') 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}.`) } } 这里 如果按照平时的写法,我肯定会用很多的if来进行判断,这样子反而增加了代码量,而且不美观。比如这样: export default function(mapDispatchToProps){ let result = undefined; result = whenMapDispatchToPropsIsFunction(mapDispatchToProps); if(!result) result = whenMapDispatchToPropsIsMissing(mapDispatchToProps); if(!result) result = whenMapDispatchToPropsIsObject(mapDispatchToProps); return result; } 和源码里的比较,感觉还是源码里写的好看,有趣。 mapStateToProps.js这个JS中提供了两个方法,分别应对mapDispatchToProps是function和null的情况。 whenMapStateToPropsIsFunctionexport function whenMapStateToPropsIsFunction(mapStateToProps) { return (typeof mapStateToProps === 'function') ? wrapMapToPropsFunc(mapStateToProps,'mapStateToProps') : undefined } 当mapStateToProps是function的时候,进行封装。这里返回的结果是 whenMapStateToPropsIsMissingexport function whenMapStateToPropsIsMissing(mapStateToProps) { return (!mapStateToProps) ? wrapMapToPropsConstant(() => ({})) : undefined } 这里,当mapStateToProps是null的时候,返回结果是 export defaultexport default [ whenMapStateToPropsIsFunction,whenMapStateToPropsIsMissing ] mergeProps.js这个JS中提供了两个方法,分别应对mergeProps是function和null的情况。 插一段mergeProps的文档:
defaultMergePropsexport function defaultMergeProps(stateProps,dispatchProps,ownProps) { return { ...ownProps,...stateProps,...dispatchProps } } 默认的mergeProps方法。和文档中说的一样,不用解释。 wrapMergePropsFuncexport function wrapMergePropsFunc(mergeProps) { return function initMergePropsProxy( dispatch,{ displayName,pure,areMergedPropsEqual } // 后面的其实都是option里面东西 ) { let hasRunOnce = false // 第一次不用检查,直接赋值,所以有一个flag let mergedProps // 记录props,用于赋值和对比 return function mergePropsProxy(stateProps,ownProps) { const nextMergedProps = mergeProps(stateProps,ownProps) if (hasRunOnce) { if (!pure || !areMergedPropsEqual(nextMergedProps,mergedProps)) mergedProps = nextMergedProps } else { hasRunOnce = true mergedProps = nextMergedProps if (process.env.NODE_ENV !== 'production') verifyPlainObject(mergedProps,'mergeProps') } return mergedProps } } } 在这里先说一下pure这个option
这里做了几件事情:
export defaultexport function whenMergePropsIsFunction(mergeProps) { return (typeof mergeProps === 'function') ? wrapMergePropsFunc(mergeProps) : undefined } export function whenMergePropsIsOmitted(mergeProps) { return (!mergeProps) ? () => defaultMergeProps : undefined } export default [ whenMergePropsIsFunction,whenMergePropsIsOmitted ] 和之前的几个js一样,包含isFunction和isOmitted两个方法。 一点总结
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |