庖丁解牛React-Redux(二): connect
connect API 上篇文章庖丁解牛React-Redux(一): connectAdvanced介绍了react-redux的 最开始我们还是来介绍一下 connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options]) 将React组件连接到Redux store, 参数:
如果你的
如果传入参数是一个对象,对象中的每个函数都被认为是Redux的action creator函数。返回的对象中的每个action creator函数都会被 如果传递一个函数,该函数的第一个参数为 如果你的 如果没有传入自定义的
如果指定了这个参数,传入的参数为:函数
connect源码 export function createConnect({ connectHOC = connectAdvanced,mapStateToPropsFactories = defaultMapStateToPropsFactories,mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,mergePropsFactories = defaultMergePropsFactories,selectorFactory = defaultSelectorFactory } = {}) { return function connect( mapStateToProps,mapDispatchToProps,mergeProps,{ pure = true,areStatesEqual = strictEqual,areOwnPropsEqual = shallowEqual,areStatePropsEqual = shallowEqual,areMergedPropsEqual = shallowEqual,...extraOptions } = {} ) { const initMapStateToProps = match(mapStateToProps,mapStateToPropsFactories,'mapStateToProps') const initMapDispatchToProps = match(mapDispatchToProps,mapDispatchToPropsFactories,'mapDispatchToProps') const initMergeProps = match(mergeProps,mergePropsFactories,'mergeProps') return connectHOC(selectorFactory,{ methodName: 'connect',getDisplayName: name => `Connect(${name})`,shouldHandleStateChanges: Boolean(mapStateToProps),initMapStateToProps,initMapDispatchToProps,initMergeProps,pure,areStatesEqual,areOwnPropsEqual,areStatePropsEqual,areMergedPropsEqual,...extraOptions }) } } const connect = createConnect(); connectHOC 传入用来生成连接到store的高阶组件(HOC),默认是之前介绍过的 selectorFactory selectorFactory(dispatch,factoryOptions): selector(state,ownProps): props (Function) 我们来看看 const selectorFactory = finalPropsSelectorFactory(dispatch,{ initMapStateToProps,...options }) { const mapStateToProps = initMapStateToProps(dispatch,options) const mapDispatchToProps = initMapDispatchToProps(dispatch,options) const mergeProps = initMergeProps(dispatch,options) if (process.env.NODE_ENV !== 'production') { verifySubselectors(mapStateToProps,options.displayName) } const selectorFactory = options.pure ? pureFinalPropsSelectorFactory : impureFinalPropsSelectorFactory return selectorFactory( mapStateToProps,dispatch,options ) } function impureFinalPropsSelectorFactory( mapStateToProps,dispatch ) { return function impureFinalPropsSelector(state,ownProps) { return mergeProps( mapStateToProps(state,ownProps),mapDispatchToProps(dispatch,ownProps ) } } 我们知道, pureFinalPropsSelectorFactory( mapStateToProps,{ areStatesEqual,areStatePropsEqual } ) { let hasRunAtLeastOnce = false let state let ownProps let stateProps let dispatchProps let mergedProps // ...... return function pureFinalPropsSelector(nextState,nextOwnProps) { return hasRunAtLeastOnce ? handleSubsequentCalls(nextState,nextOwnProps) : handleFirstCall(nextState,nextOwnProps) } } 函数 function handleFirstCall(firstState,firstOwnProps) { state = firstState ownProps = firstOwnProps stateProps = mapStateToProps(state,ownProps) dispatchProps = mapDispatchToProps(dispatch,ownProps) mergedProps = mergeProps(stateProps,ownProps) hasRunAtLeastOnce = true return mergedProps } function handleSubsequentCalls(nextState,nextOwnProps) { const propsChanged = !areOwnPropsEqual(nextOwnProps,ownProps) const stateChanged = !areStatesEqual(nextState,state) state = nextState ownProps = nextOwnProps if (propsChanged && stateChanged) return handleNewPropsAndNewState() if (propsChanged) return handleNewProps() if (stateChanged) return handleNewState() return mergedProps } 再看函数 function handleNewPropsAndNewState() { stateProps = mapStateToProps(state,ownProps) if (mapDispatchToProps.dependsOnOwnProps) dispatchProps = mapDispatchToProps(dispatch,ownProps) mergedProps = mergeProps(stateProps,ownProps) return mergedProps } 我们看到,如果props和state都发送改变了,调用了 function handleNewProps() { if (mapStateToProps.dependsOnOwnProps) stateProps = mapStateToProps(state,ownProps) return mergedProps } 理解了 function handleNewState() { const nextStateProps = mapStateToProps(state,ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps,stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps,ownProps) return mergedProps } mapStateToProps起源 看完了 //connect.js // initMapStateToProps会被传入 selectorFactory const initMapStateToProps = match(mapStateToProps,'mapStateToProps')
//selectorFactory.js const mapStateToProps = initMapStateToProps(dispatch,options) //mapStateToProps的使用(注意这里的mapStateToProps不是传入的函数,而是init函数生成的函数): const stateProps = mapStateToProps(state,ownProps) 我们可以看到,首先在 首先看 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}.`) } } 接下来的内容相对来说会比较复杂,我们先提前梳理一下 (dispatch,options)=>{ //.... return ()=>{ } } 这个返回的函数接受 (state,ownProps) =>{ //...... //return plain object } 这个函数将用来计算新的state传递给被包裹的组件。 对于 const initMapStateToProps = match(mapStateToProps,'mapStateToProps') const mapStateToPropsFactories = [ whenMapStateToPropsIsFunction,whenMapStateToPropsIsMissing ]; function whenMapStateToPropsIsFunction(mapStateToProps) { return (typeof mapStateToProps === 'function') ? wrapMapToPropsFunc(mapStateToProps,'mapStateToProps') : undefined } function whenMapStateToPropsIsMissing(mapStateToProps) { return (!mapStateToProps) ? wrapMapToPropsConstant(() => ({})) : undefined } 上面的代码都不难,首先判断传入的 function wrapMapToPropsConstant(getConstant) { return function initConstantSelector(dispatch,options) { const constant = getConstant(dispatch,options) function constantSelector() { return constant } constantSelector.dependsOnOwnProps = false return constantSelector } } 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 = true proxy.mapToProps = function detectFactoryAndVerify(stateOrDispatch,ownProps) { proxy.mapToProps = mapToProps proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps) let props = proxy(stateOrDispatch,ownProps) if (typeof props === 'function') { proxy.mapToProps = props proxy.dependsOnOwnProps = getDependsOnOwnProps(props) props = proxy(stateOrDispatch,ownProps) } if (process.env.NODE_ENV !== 'production') verifyPlainObject(props,displayName,methodName) return props } return proxy } } mapDispatchToProps起源 //connect.js const initMapDispatchToProps = match(mapDispatchToProps,'mapDispatchToProps') //selectFactory const mapDispatchToProps = initMapDispatchToProps(dispatch,options) //使用: const dispatchProps = mapDispatchToProps(dispatch,ownProps) 其实 const mapDispatchToPropsFactories = [ whenMapDispatchToPropsIsFunction,whenMapDispatchToPropsIsMissing,whenMapDispatchToPropsIsObject ] function whenMapDispatchToPropsIsFunction(mapDispatchToProps) { return (typeof mapDispatchToProps === 'function') ? wrapMapToPropsFunc(mapDispatchToProps,'mapDispatchToProps') : undefined } function whenMapDispatchToPropsIsMissing(mapDispatchToProps) { return (!mapDispatchToProps) ? wrapMapToPropsConstant(dispatch => ({ dispatch })) : undefined } function whenMapDispatchToPropsIsObject(mapDispatchToProps) { return (mapDispatchToProps && typeof mapDispatchToProps === 'object') ? wrapMapToPropsConstant(dispatch => bindActionCreators(mapDispatchToProps,dispatch)) : undefined } 如果你已经看懂了 如果没有传入 mergeProps起源//connect.js const initMergeProps = match(mergeProps,'mergeProps') //selectorFactory const mergeProps = initMergeProps(dispatch,options) //使用 mergedProps = mergeProps(stateProps,ownProps) const mergePropsFactories = [ whenMergePropsIsFunction,whenMergePropsIsOmitted ] function whenMergePropsIsFunction(mergeProps) { return (typeof mergeProps === 'function') ? wrapMergePropsFunc(mergeProps) : undefined } function whenMergePropsIsOmitted(mergeProps) { return (!mergeProps) ? () => defaultMergeProps : undefined } 如果你没有传入 function defaultMergeProps(stateProps,ownProps) { return { ...ownProps,...stateProps,...dispatchProps } } 如果你传入了 function wrapMergePropsFunc(mergeProps) { return function initMergePropsProxy(dispatch,{ displayName,areMergedPropsEqual }) { let hasRunOnce = false let mergedProps 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 } } } 到此为止,我们基本已经在代码层面讲完了 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |