react-redux/src/connect/connect.js
const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps')
const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps')
const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')
执行match,调用如下mapStateToPropsFactories,完成“业务mapToPorps”初始化操作(例如{}时补齐操作)
mapStateToPropsFactories = [
whenMapStateToPropsIsFunction,
whenMapStateToPropsIsMissing
]
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}.`)
}
}
其中一个分支:
export function whenMapStateToPropsIsFunction(mapStateToProps) {
return (typeof mapStateToProps === 'function')
? wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
: undefined
}
export function wrapMapToPropsFunc(mapToProps, methodName) {
return function initProxySelector(dispatch, { displayName }) {
const proxy = function mapToPropsProxy(stateOrDispatch, ownProps) {
// 第一次dependsOnOwnProps为true,调用mapToProp为detectFactoryAndVerify(stateOrDispatch, ownProps)
// 第二次mapToProp为“业务代码中的mapStateToProps”
return proxy.dependsOnOwnProps
? proxy.mapToProps(stateOrDispatch, ownProps)
: proxy.mapToProps(stateOrDispatch)
}
// allow detectFactoryAndVerify to get ownProps
proxy.dependsOnOwnProps = true
proxy.mapToProps = function detectFactoryAndVerify(stateOrDispatch, ownProps) {
// mapToProps被重新赋值为“业务代码中的mapStateToProps”
proxy.mapToProps = mapToProps
proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps)
let props = proxy(stateOrDispatch, ownProps)
if (typeof props === 'function') {
// mapToProps被重新赋值为“业务代码中的mapStateToProps执行后的返回值”
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
}
}
=> initMapDispatchToProps = initProxySelector(dispatch, { displayName })
react-redux/src/components/connectAdvanced.js
initSelector
initSelector() {
// 1、生成sourceSelector
const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions)
// 2、包装selector
this.selector = makeSelectorStateful(sourceSelector, this.store)
// 3、state发生变化的时候调用selector,最终赋值selector.props = nextProps
this.selector.run(this.props)
}
1、生成sourceSelector connectAdvanced方法中的selectorFactory = finalPropsSelectorFactory
export default function finalPropsSelectorFactory(dispatch, {
initMapStateToProps,
initMapDispatchToProps,
initMergeProps,
...options
}) {
// 返回proxy
const mapStateToProps = initMapStateToProps(dispatch, options)
const mapDispatchToProps = initMapDispatchToProps(dispatch, options)
const mergeProps = initMergeProps(dispatch, options)
if (process.env.NODE_ENV !== 'production') {
verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps, options.displayName)
}
const selectorFactory = options.pure
? pureFinalPropsSelectorFactory
: impureFinalPropsSelectorFactory
return selectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps,
dispatch,
options
)
}
其中一个分支:重新赋值selectorFactory = pureFinalPropsSelectorFactory
export function pureFinalPropsSelectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps,
dispatch,
{ areStatesEqual, areOwnPropsEqual, areStatePropsEqual }
) {
let hasRunAtLeastOnce = false
let state
let ownProps
let stateProps
let dispatchProps
let mergedProps
function handleFirstCall(firstState, firstOwnProps) {
state = firstState
ownProps = firstOwnProps
stateProps = mapStateToProps(state, ownProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
hasRunAtLeastOnce = true
return mergedProps
}
function handleNewPropsAndNewState() {
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
function handleNewProps() {
if (mapStateToProps.dependsOnOwnProps)
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
function handleNewState() {
const nextStateProps = mapStateToProps(state, ownProps)
const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps)
stateProps = nextStateProps
if (statePropsChanged)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
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
}
return function pureFinalPropsSelector(nextState, nextOwnProps) {
return hasRunAtLeastOnce
? handleSubsequentCalls(nextState, nextOwnProps)
: handleFirstCall(nextState, nextOwnProps)
}
}
const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions) => sourceSelector = handleSubsequentCalls(nextState, nextOwnProps) 或者 handleFirstCall(nextState, nextOwnProps)
2、包装selector(错误处理+传递函数) this.selector = makeSelectorStateful(sourceSelector, this.store)
function makeSelectorStateful(sourceSelector, store) {
// wrap the selector in an object that tracks its results between runs.
const selector = {
run: function runComponentSelector(props) {
try {
const nextProps = sourceSelector(store.getState(), props)
if (nextProps !== selector.props || selector.error) {
selector.shouldComponentUpdate = true
selector.props = nextProps
selector.error = null
}
} catch (error) {
selector.shouldComponentUpdate = true
selector.error = error
}
}
}
return selector
}
=> this.selector = makeSelectorStateful中的selector
3、state发生变化的时候调用selector,最终赋值selector.props = nextProps selector.run 执行const nextProps = sourceSelector(store.getState(), props) 其中一个分支:
function handleFirstCall(firstState, firstOwnProps) {
state = firstState
ownProps = firstOwnProps
// mapStateToProps是上面的Proxy
stateProps = mapStateToProps(state, ownProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
hasRunAtLeastOnce = true
// 返回所有的props对象(包括status, dispatch)
return mergedProps
}
=>handleFirstCall(firstState, firstOwnProps) 返回的mergeProps最终传递给connect()(WrappedComponent)中的WrappedComponent
- react-redux/src/components/connectAdvanced/Connect.render
render() {
return createElement(WrappedComponent, this.addExtraProps(selector.props))
}
initSubscription
- react-redux/src/utils/Subscription.js
addNestedSub(listener) {
this.trySubscribe()
// 下层Container的onStatechange存储在react-redux中
return this.listeners.subscribe(listener)
}
trySubscribe() {
if (!this.unsubscribe) {
// 没有父级观察者的话,直接监听store change
// 有的话,添到父级下面,由父级传递变化
this.unsubscribe = this.parentSub
? this.parentSub.addNestedSub(this.onStateChange)
// container的onStatechange存储在redux中
: this.store.subscribe(this.onStateChange)
this.listeners = createListenerCollection()
}
}
react-redux调用store.subscribe(redux通过createstore从生成的store),只对顶层Container直接监听了state change,下层Container都是内部传递通知的.
- react-redux/src/components/connectAdvanced/Connect.onStateChange
onStateChange() {
// state change时重新计算props
this.selector.run(this.props)
// 当前组件不用更新的话,通知下方container检查更新
// 要更新的话,setState空对象强制更新,延后通知到didUpdate
if (!this.selector.shouldComponentUpdate) {
this.notifyNestedSubs()
} else {
this.componentDidUpdate = this.notifyNestedSubsOnComponentDidUpdate
// 通知Container下方的view更新
//!!! 这里是把redux与react连接起来的关键
this.setState(dummyState)
}
}
最重要的那个setState就在这里,dispatch action后视图更新的秘密是这样:
1.dispatch action
2.redux计算reducer得到newState
3.redux触发state change(调用之前通过store.subscribe注册的state变化监听器)
4.react-redux顶层Container的onStateChange触发
1.重新计算props
2.比较新值和缓存值,看props变了没,要不要更新
3.要的话通过setState({})强制react更新
4.通知下方的subscription,触发下方关注state change的Container的onStateChange,检查是否需要更新view
- react-redux/src/components/connectAdvanced/Connect.render
render() {
return createElement(WrappedComponent, this.addExtraProps(selector.props))
}
根据WrappedComponent需要的state字段,造一份props,通过React.createElement注入进去。ContainerInstance.setState({})时,这个render函数被重新调用,新的props被注入到view,view will receive props…视图更新就真正开始了