react-redux 源码解析(1) -- Provider
react-redux 源码解析(2) -- Connect(上)
react-redux 源码解析(3) -- Connect(下)
---------------------------------------分割线-----------------------------------------
续接上文,我们分析了Provider。既然Provider已经准备完毕,我们就要开始是用它。中间我们定然会用到dispathc推送state改变store的值,那么我们接下来就来看看如何向组件注入state和dispatch。
我们先来看看它是如何使用的,上代码:
class Home extends Component<props, any>{
componentDidMount(){
console.log(this.props)
}
render(){
return (
<div></div>
)
}
}
export default connect((state)=>({...state}), (dispatch)=>({dispatch}))(Home);
使用还是很简单,看的出来connect是个HOC,传入组件,注入state和dispathc。 这里就没什么多讲的了,我们还是直接来看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, {
// used in error messages
methodName: 'connect',
// used to compute Connect's displayName from the wrapped component's displayName.
getDisplayName: (name) => `Connect(${name})`,
// if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes
shouldHandleStateChanges: Boolean(mapStateToProps),
// passed through to selectorFactory
initMapStateToProps,
initMapDispatchToProps,
initMergeProps,
pure,
areStatesEqual,
areOwnPropsEqual,
areStatePropsEqual,
areMergedPropsEqual,
// any extra options args can override defaults of connect or connectAdvanced
...extraOptions,
})
}
}
export default /*#__PURE__*/ createConnect()
返回的是createConnect执行的结果,也就是 connect函数,不过有五个参数参数,在调用 createConnect就已经注入了,分别是: connectHOC、mapStateToPropsFactories、mapDispatchToPropsFactories、mergePropsFactories、selectorFactory。默认值分别是connectAdvanced、defaultMapStateToPropsFactories、defaultMapDispatchToPropsFactories、defaultMergePropsFactories、defaultSelectorFactory。我们继续往下看,等到了调用的时候,咱们在贴上源码,逐一分析。
const initMapStateToProps = match(
mapStateToProps,
mapStateToPropsFactories,
'mapStateToProps'
)
const initMapDispatchToProps = match(
mapDispatchToProps,
mapDispatchToPropsFactories,
'mapDispatchToProps'
)
const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')
看得到一开始就定义了三个常量。我们先来看第一个initMapStateToProps,调用了match函数,传入了上文提到的defaultMapStateToPropsFactories函数。那么他们到底干了什么?不墨迹,上源码:
match 函数
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
}.`
)
}
}
-----------------------
defaultMapStateToPropsFactories 函数
import { wrapMapToPropsConstant, wrapMapToPropsFunc } from './wrapMapToProps'
export function whenMapStateToPropsIsFunction(mapStateToProps) {
return typeof mapStateToProps === 'function'
? wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
: undefined
}
export function whenMapStateToPropsIsMissing(mapStateToProps) {
return !mapStateToProps ? wrapMapToPropsConstant(() => ({})) : undefined
}
export default [whenMapStateToPropsIsFunction, whenMapStateToPropsIsMissing]
看的出来 defaultMapStateToPropsFactories返回的是个函数数组, match 是个循环调用函数数组的函数。返回wrapMapToPropsConstant或者 wrapMapToPropsFunc函数调用的返回。第一个函数中如果mapStateToProps是函数那么就返回 wrapMapToPropsFunc调用如果不是就返回undefined。第二个函数中,如果优质就返回wrapMapToPropsConstant调用,其他返回undefined。逻辑还是清晰的。 我们这边只考虑mapStateToProps为非空且为函数的情况。我们来看看wrapMapToPropsFunc函数,上代码
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)
}
// allow detectFactoryAndVerify to get ownProps
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
}
}
wrapMapToPropsFunc的函数相对来说比较复杂,接受的参数是你传入的mapStateToProps函数(methodName的作用只是错误提示),返回的是初始化selector函数(initProxySelector)。当使用initProxySelector初始化selector的时候,返回的函数proxy实则为一个代理(proxy)。第一次执行proxy(selector)时,dependsOnOwnProps的值为true,所以相当于执行proxy.mapToProps(stateOrDispatch, ownProps)(detectFactoryAndVerify),然后将proxy.mapToProps属性设置为你所传入的mapStateToProps函数。这时候再去执行getDependsOnOwnProps的目的是去确定你传入的mapStateToProps是否需要传入props。然后再去执行proxy(stateOrDispatch, ownProps),这时候proxy.mapToProps已经不是之前的detectFactoryAndVerify而是你传入的mapStateToProps(所以不会出现死循环)。执行的结果就是mapStateToProps运行后的结果。如果prop是对象,将会直接传递给被包裹组件。但是我们之前讲过,mapStateToProps是可以返回一个函数的,如果返回的值为一个函数,这个函数将会被作为proxy的mapStateToProps,再次去执行proxy。
接下来的initMapDispatchToProps其实和此类似,同学们可以自行看看。
再来看一下mergePropsFactories是怎么定义的,我们主要还是看非空的情况,上代码:
export function wrapMergePropsFunc(mergeProps) {
return function initMergePropsProxy(
dispatch,
{ displayName, pure, areMergedPropsEqual }
) {
let hasRunOnce = false
let mergedProps
return function mergePropsProxy(stateProps, dispatchProps, ownProps) {
const nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps)
if (hasRunOnce) {
if (!pure || !areMergedPropsEqual(nextMergedProps, mergedProps))
mergedProps = nextMergedProps
} else {
hasRunOnce = true
mergedProps = nextMergedProps
if (process.env.NODE_ENV !== 'production')
verifyPlainObject(mergedProps, displayName, 'mergeProps')
}
return mergedProps
}
}
}
wrapMergePropsFunc中涉及到性能优化,首先wrapMergePropsFunc返回一个初始mergeProps的函数(mergePropsProxy)。函数mergePropsProxy闭包一个变量hasRunOnce来记录mergeProps运行次数,在mergeProps第一次运行时,会保存第一次传入被包裹组件的的props,再以后的运行过程中,如果你传入的参数pure为true并且前后的mergedProps值不同时(比较函数你可以自定义)才会传入新的属性,否则将传入之前的缓存值,以此来优化不必要的渲染。
接下来就是传入参数,返回connectAdvanced方法调用。它就是我们connect的具体实现,我们在下一章中详细讲解,敬请期待。