Created
November 12, 2015 12:11
-
-
Save troch/520eb25dce170a69758a to your computer and use it in GitHub Desktop.
Deku connect
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import element from 'virtual-element'; | |
import { bindActionCreators } from 'redux'; | |
import shallowEquals from 'is-equal-shallow'; | |
import isPlainObject from 'is-plain-object'; | |
const defaultMapStateToProps = () => ({}) | |
const defaultMapDispatchToProps = dispatch => ({ dispatch }) | |
const defaultMergeProps = (stateProps, dispatchProps, parentProps) => ({ | |
...parentProps, | |
...stateProps, | |
...dispatchProps | |
}); | |
const wrapActionCreators = actionCreators => dispatch => bindActionCreators(actionCreators, dispatch); | |
function connect(mapStateToProps = defaultMapStateToProps, mapDispatchToProps = defaultMapDispatchToProps, mergeProps = defaultMergeProps) { | |
if(isPlainObject(mapDispatchToProps)) { | |
mapDispatchToProps = wrapActionCreators(mapDispatchToProps); | |
} | |
const mappedStateUseProps = mapStateToProps.length > 1; | |
const mappedDispatchUseProps = mapDispatchToProps.length > 1; | |
const computeStateProps = props => { | |
const state = props.store.getState(); | |
const stateProps = mapStateToProps(state, props); | |
// TODO: invariant(plainObject) | |
return stateProps; | |
}; | |
const computeDispatchProps = props => { | |
const dispatch = props.store.dispatch; | |
const dispatchProps = mapDispatchToProps(dispatch, props); | |
// TODO: invariant(plainObject) | |
return dispatchProps; | |
}; | |
return function connectWrapper(Component) { | |
const connectRegistry = {}; | |
const getStateProps = id => connectRegistry[id] ? connectRegistry[id].stateProps : null; | |
const setStateProps = (id, stateProps) => connectRegistry[id].stateProps = stateProps; | |
const getDispatchProps = id => connectRegistry[id] ? connectRegistry[id].dispatchProps : null; | |
const setDispatchProps = (id, dispatchProps) => connectRegistry[id].dispatchProps = dispatchProps; | |
const ConnectedComponent = { | |
propTypes: { | |
store: { source: 'store' }, | |
storeState: { source: 'storeState' } | |
}, | |
afterMount({ id, props }, elm, setState) { | |
// TODO: invariant store | |
connectRegistry{id} = {}; | |
setStateProps(id, computeStateProps(props)); | |
setDispatchProps(id, computeDispatchProps(props)); | |
}, | |
shouldUpdate({ id, props }, nextProps) { | |
const storeChanged = nextState.storeState !== state.storeState; | |
const propsChanged = !shallowEquals(nextProps, props); | |
const computeNewStateProps = storeChanged || (propsChanged && mappedStateUseProps); | |
const computeNewDispatchProps = propsChanged && mappedDispatchUseProps; | |
let statePropsChanged = false; | |
let dispatchPropsChanged = false; | |
if (computeNewStateProps) { | |
const stateProps = computeStateProps(props); | |
statePropsChanged = !shallowEquals(stateProps, getStateProps(id)); | |
if (statePropsChanged) { | |
setStateProps(id, stateProps); | |
} | |
} | |
if (computeNewDispatchProps) { | |
const dispatchProps = computeDispatchProps(props); | |
dispatchPropsChanged = !shallowEquals(dispatchProps, getDispatchProps(id)); | |
if (dispatchPropsChanged) { | |
setDispatchProps(id, stateProps); | |
} | |
} | |
return propsChanged || statePropsChanged || dispatchPropsChanged; | |
}, | |
beforeUnmount({ id }) { | |
connectRegistry{id} = undefined; | |
}, | |
render({ id, props }) { | |
// TODO: use _.omit or similar | |
const parentProps = Object.keys(props) | |
.filter(prop => prop !== 'store' || prop !== 'storeState'); | |
.reduce((acc, prop) => { | |
acc[prop] = props[prop]; | |
return acc; | |
}, {}); | |
return element(Component, { ...parentProps, ...getStateProps(id), ...getDispatchProps(id) }); | |
} | |
}; | |
return ConnectedComponent; | |
}; | |
} | |
export default connect; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment