Skip to content

Commit

Permalink
connect() wraps connectFactory(), attaching prop configuration to com…
Browse files Browse the repository at this point in the history
…ponent
  • Loading branch information
tgriesser committed Nov 11, 2015
1 parent 777652d commit 25f97c7
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 59 deletions.
125 changes: 67 additions & 58 deletions src/components/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,58 +21,15 @@ function getDisplayName(WrappedComponent) {
// Helps track hot reloading.
let nextVersion = 0

export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
const shouldSubscribe = Boolean(mapStateToProps)
const finalMapStateToProps = mapStateToProps || defaultMapStateToProps
const finalMapDispatchToProps = isPlainObject(mapDispatchToProps) ?
wrapActionCreators(mapDispatchToProps) :
mapDispatchToProps || defaultMapDispatchToProps
export function connectFactory(mapStateToPropsFactory, mapDispatchToPropsFactory, mergeProps, options = {}) {
const finalMergeProps = mergeProps || defaultMergeProps
const shouldUpdateStateProps = finalMapStateToProps.length > 1
const shouldUpdateDispatchProps = finalMapDispatchToProps.length > 1
const finalMapStateToPropsFactory = mapStateToPropsFactory || () => defaultMapStateToProps
const finalMapDispatchToPropsFactory = mapDispatchToPropsFactory || () => defaultMapDispatchToProps
const { pure = true, withRef = false } = options

// Helps track hot reloading.
const version = nextVersion++

function computeStateProps(store, props) {
const state = store.getState()
const stateProps = shouldUpdateStateProps ?
finalMapStateToProps(state, props) :
finalMapStateToProps(state)

invariant(
isPlainObject(stateProps),
'`mapStateToProps` must return an object. Instead received %s.',
stateProps
)
return stateProps
}

function computeDispatchProps(store, props) {
const { dispatch } = store
const dispatchProps = shouldUpdateDispatchProps ?
finalMapDispatchToProps(dispatch, props) :
finalMapDispatchToProps(dispatch)

invariant(
isPlainObject(dispatchProps),
'`mapDispatchToProps` must return an object. Instead received %s.',
dispatchProps
)
return dispatchProps
}

function computeNextState(stateProps, dispatchProps, parentProps) {
const mergedProps = finalMergeProps(stateProps, dispatchProps, parentProps)
invariant(
isPlainObject(mergedProps),
'`mergeProps` must return an object. Instead received %s.',
mergedProps
)
return mergedProps
}

return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
shouldComponentUpdate(nextProps, nextState) {
Expand All @@ -88,11 +45,11 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
let mapStateProducedChange = false
let dispatchPropsChanged = false

if (storeChanged || (propsChanged && shouldUpdateStateProps)) {
if (storeChanged || (propsChanged && this.shouldUpdateStateProps)) {
mapStateProducedChange = this.updateStateProps(nextProps)
}

if (propsChanged && shouldUpdateDispatchProps) {
if (propsChanged && this.shouldUpdateDispatchProps) {
dispatchPropsChanged = this.updateDispatchProps(nextProps)
}

Expand All @@ -116,22 +73,61 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
`or explicitly pass "store" as a prop to "${this.constructor.displayName}".`
)

this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.configure()
this.stateProps = this.computeStateProps()
this.dispatchProps = this.computeDispatchProps()
this.state = { storeState: null }
this.updateState()
}

computeNextState(props = this.props) {
return computeNextState(
this.stateProps,
this.dispatchProps,
props
configure() {
this.shouldSubscribe = Boolean(mapStateToPropsFactory)
this.finalMapStateToProps = finalMapStateToPropsFactory()
this.finalMapDispatchToProps = finalMapDispatchToPropsFactory()
this.shouldUpdateStateProps = this.finalMapStateToProps.length > 1
this.shouldUpdateDispatchProps = this.finalMapDispatchToProps.length > 1
}

computeStateProps(props = this.props) {
const state = this.store.getState()
const stateProps = this.shouldUpdateStateProps ?
this.finalMapStateToProps(state, props) :
this.finalMapStateToProps(state)

invariant(
isPlainObject(stateProps),
'`mapStateToProps` must return an object. Instead received %s.',
stateProps
)
return stateProps
}

computeDispatchProps(props = this.props) {
const { dispatch } = this.store
const dispatchProps = this.shouldUpdateDispatchProps ?
this.finalMapDispatchToProps(dispatch, props) :
this.finalMapDispatchToProps(dispatch)

invariant(
isPlainObject(dispatchProps),
'`mapDispatchToProps` must return an object. Instead received %s.',
dispatchProps
)
return dispatchProps
}

computeNextState(parentProps = this.props) {
const mergedProps = finalMergeProps(this.stateProps, this.dispatchProps, parentProps)
invariant(
isPlainObject(mergedProps),
'`mergeProps` must return an object. Instead received %s.',
mergedProps
)
return mergedProps
}

updateStateProps(props = this.props) {
const nextStateProps = computeStateProps(this.store, props)
const nextStateProps = this.computeStateProps(props)
if (shallowEqual(nextStateProps, this.stateProps)) {
return false
}
Expand All @@ -141,7 +137,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
}

updateDispatchProps(props = this.props) {
const nextDispatchProps = computeDispatchProps(this.store, props)
const nextDispatchProps = this.computeDispatchProps(props)
if (shallowEqual(nextDispatchProps, this.dispatchProps)) {
return false
}
Expand All @@ -159,7 +155,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
}

trySubscribe() {
if (shouldSubscribe && !this.unsubscribe) {
if (this.shouldSubscribe && !this.unsubscribe) {
this.unsubscribe = this.store.subscribe(::this.handleChange)
this.handleChange()
}
Expand Down Expand Up @@ -226,6 +222,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
this.version = version

// Update the state and bindings.
this.configure()
this.trySubscribe()
this.updateStateProps()
this.updateDispatchProps()
Expand All @@ -236,3 +233,15 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
return hoistStatics(Connect, WrappedComponent)
}
}

export function connect(mapStateToProps, mapDispatchToProps, mergeProps, options) {
const configuredMapDispatch = isPlainObject(mapDispatchToProps) ?
wrapActionCreators(mapDispatchToProps) :
mapDispatchToProps
return connectFactory(
mapStateToProps ? () => mapStateToProps : null,
configuredMapDispatch ? () => configuredMapDispatch : null,
mergeProps,
options
)
}
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { default as Provider } from './components/Provider'
export { default as connect } from './components/connect'
export { connect, connectFactory } from './components/connect'

0 comments on commit 25f97c7

Please sign in to comment.