Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connectComponent, attaching prop configuration to component #185

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 70 additions & 53 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 connectComponent(mapStateToPropsFactory, mapDispatchToPropsFactory, mergeProps, options = {}) {
const finalMapStateToPropsFactory = mapStateToPropsFactory || (() => defaultMapStateToProps)
const finalMapDispatchToPropsFactory = mapDispatchToPropsFactory || (() => defaultMapDispatchToProps)
const finalMergeProps = mergeProps || defaultMergeProps
const doStatePropsDependOnOwnProps = finalMapStateToProps.length !== 1
const doDispatchPropsDependOnOwnProps = finalMapDispatchToProps.length !== 1
const { pure = true, withRef = false } = options

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

function computeStateProps(store, props) {
const state = store.getState()
const stateProps = doStatePropsDependOnOwnProps ?
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 = doDispatchPropsDependOnOwnProps ?
finalMapDispatchToProps(dispatch, props) :
finalMapDispatchToProps(dispatch)

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

function computeMergedProps(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() {
Expand All @@ -91,13 +48,60 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
`or explicitly pass "store" as a prop to "${this.constructor.displayName}".`
)

this.configure()
const storeState = this.store.getState()
this.state = { storeState }
this.clearCache()
}

configure() {
this.shouldSubscribe = Boolean(mapStateToPropsFactory)
this.finalMapStateToProps = finalMapStateToPropsFactory()
this.finalMapDispatchToProps = finalMapDispatchToPropsFactory()
this.doStatePropsDependOnOwnProps = this.finalMapStateToProps.length !== 1
this.doDispatchPropsDependOnOwnProps = this.finalMapDispatchToProps.length !== 1
}

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

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

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

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

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

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

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

updateMergedProps() {
this.mergedProps = computeMergedProps(
this.mergedProps = this.computeMergedProps(
this.stateProps,
this.dispatchProps,
this.props
Expand All @@ -129,8 +133,8 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
}

trySubscribe() {
if (shouldSubscribe && !this.unsubscribe) {
this.unsubscribe = this.store.subscribe(::this.handleChange)
if (this.shouldSubscribe && !this.unsubscribe) {
this.unsubscribe = this.store.subscribe(() => this.handleChange())
this.handleChange()
}
}
Expand Down Expand Up @@ -203,10 +207,10 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
let shouldUpdateDispatchProps = true
if (pure && renderedElement) {
shouldUpdateStateProps = hasStoreStateChanged || (
haveOwnPropsChanged && doStatePropsDependOnOwnProps
haveOwnPropsChanged && this.doStatePropsDependOnOwnProps
)
shouldUpdateDispatchProps =
haveOwnPropsChanged && doDispatchPropsDependOnOwnProps
haveOwnPropsChanged && this.doDispatchPropsDependOnOwnProps
}

let haveStatePropsChanged = false
Expand Down Expand Up @@ -265,6 +269,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,

// We are hot reloading!
this.version = version
this.configure()
this.trySubscribe()
this.clearCache()
}
Expand All @@ -273,3 +278,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 connectComponent(
mapStateToProps ? (() => mapStateToProps) : null,
configuredMapDispatch ? (() => configuredMapDispatch) : null,
mergeProps,
options
)
}
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Provider from './components/Provider'
import connect from './components/connect'
import { connect, connectComponent } from './components/connect'

export { Provider, connect }
export { Provider, connect, connectComponent }