react-redux 源码解读之connect的mapDispatchToProps
connect对于mapDispatchToProps的处理跟mapStateToProps的处理流程是一样的,只有一点点差别,理解mapDispatchToProps时,可以结合mapStateToProps来理解。
以这样写法的mapDispatchToProps为例讨论
const faActionCreators = {
abc:aaa=>{
return {
type:'ADD',
id:num++,
text:aaa,
}
},
qqw:aaa=>({
type:'TYY',
id:num++,
text:aaa,
}),
noa:aaa=>({
type:'nono',
id:num++,
text:aaa,
})
}
const mapDispatchToProps = faActionCreators;
在connectAdvanced.js的Connect组件中:
constructor内,定义了
this.initSelector();
从而会执行一次
const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions)
而且在Connect组件中,只在此时执行一次selectorFactory,以后都不会执行。
selectorFactory()
就是执行
selectorFactory.js 的 finalPropsSelectorFactory()
从而执行一次
const mapDispatchToProps = initMapDispatchToProps(dispatch, options)
initMapDispatchToProps其实就是
wrapMapToProps.js的initConstantSelector;
组件在整个装载更新销毁过程当中只会执行一次 selectorFactory;因此只会执行一次finalPropsSelectorFactory(),因此只会执行一次initConstantSelector();
//initConstantSelector方法:
return function initConstantSelector(dispatch, options) {
const constant = getConstant(dispatch, options)
function constantSelector() { return constant }
constantSelector.dependsOnOwnProps = false
return constantSelector
}
getConstant方法为:
//getConstant方法
dispatch => bindActionCreators(mapDispatchToProps, dispatch)
const mapDispatchToProps
= initMapDispatchToProps(dispatch, options)
这里的mapDispatchToProps
其实就是函数 constantSelector,从代码看,此函数不做任何事情,它是一个闭包函数,只是单纯从initMapDispatchToProps母函数中取数据,
而constant其实就是包装好的mapDispatchToProps:
{abc: ƒ, qqw: ƒ, noa: ƒ}
在selectorFactory.js中
dispatchProps = mapDispatchToProps(dispatch, ownProps)
相当于
dispatchProps = constantSelector(dispatch, ownProps)
可以看出dispatch, ownProps这两个参数是多余传递的。
执行selectorFactory.js中的 dispatchProps = mapDispatchToProps(dispatch, ownProps),并没有做任何事情,只是单纯获取已经在组件装载时已经包装好的mapDispatchToProps。
由于initConstantSelector从始至终只执行一次,所以,对于外层定义的mapDispatchToProps包装,只进行一次。
initConstantSelector与bindActionCreator
//initConstantSelector方法:
return function initConstantSelector(dispatch, options) {
const constant = getConstant(dispatch, options)
function constantSelector() { return constant }
constantSelector.dependsOnOwnProps = false
return constantSelector
}
从代码看,initConstantSelector做了两件事:
1、返回一个constantSelector闭包函数;
2、执行getConstant(dispatch, options)获得constant,其目的就是存储好给闭包函数constantSelector使用
getConstant方法为:
//getConstant方法
dispatch => bindActionCreators(mapDispatchToProps, dispatch)
本文示例中,
actionCreators = faActionCreators;
export default function bindActionCreators(actionCreators, dispatch) {
const keys = Object.keys(actionCreators)
const boundActionCreators = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}
本文示例中,
actionCreator = aaa=>{
return {
type:'ADD',
id:num++,
text:aaa,
}
};
function bindActionCreator(actionCreator, dispatch) {
return function() {
//很妙的一个用法,通过apply与arguments,父函数可以达到最轻松自由灵活的使用子函数actionCreator
// 最终外层发送dispatch时,都会断点进入到这里
return dispatch(actionCreator.apply(this, arguments))
}
}
mapDispatchToProps小结
mapDispatchToProps的包装只会在组件装载时,在构造函数中包装一次,以后直至组件销毁,不会再做包装的工作。
在在selectorFactory.js中
dispatchProps = mapDispatchToProps(dispatch, ownProps)并没有做任何事情,只是单纯获取已经在组件装载时已经包装好的mapDispatchToProps;
因为组件更新的时候,会执行this.selector.run(this.props),根据条件不同,可能会执行到 dispatchProps = mapDispatchToProps(dispatch, ownProps),就算这个代码执行了,也不会再次包装mapDispatchToProps,而只是简单的取数据而已。
mapDispatchToProps被包装后,最终的模样是什么,包装成的模样其实就是bindActionCreator源码写的(上文已经提到),直接给出包装后最终模样:
const mapDispatchToProps = (dispatch)=>{
return {
abc:aaa=>{
dispatch({
type:'ADD',
id:num++,
text:aaa,
})
}}
如果好奇,可以在bindActionCreator源码断点查看。
mapDispatchToProps 与 mapStateToProps的不同
组件更新,会执行this.selector.run(this.props);
会触发selectorFactory.js中都会执行
mapDispatchToProps(dispatch, ownProps)
mapStateToProps(state, ownProps)
但是只有组件装载过程中,第一次运行this.selector.run,才会执行同时执行
dispatchProps = mapDispatchToProps(dispatch, ownProps) (handleFirstCall方法)
nextStateProps =mapStateToProps(state, ownProps)
这一次执行获得的dispatchProps将会被闭包保存,供以后每次this.selector.run后使用;
以后每次执行this.selector.run,基本上可以认为不再执行dispatchProps = mapDispatchToProps(dispatch, ownProps) ;
而只是从第一次存储好的闭包的上下文取dispatchProps,
但以后每次执行this.selector.run都会执行nextStateProps =mapStateToProps(state, ownProps),然后更新组件都nextStateProps;
所以组件在运行当中,dispatchProps始终是相同都,nextStateProps只要有更新是动态变化都。