Skip to content

Instantly share code, notes, and snippets.

@riquito
Created September 12, 2018 05:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save riquito/4befa64c500464b44cd7e4364dd2a840 to your computer and use it in GitHub Desktop.
Save riquito/4befa64c500464b44cd7e4364dd2a840 to your computer and use it in GitHub Desktop.
Create an higher order component that receives props from a context consumer.
/**
* Create an higher order component that receives props from a context consumer.
*
* // e.g. Create your with<SomeConsumer> function
* // const withDispatch = makeWithConsumer(DispatchContext.consumer, 'Dispatch')
*
* // e.g. pass the consumer props as they are
* const ButtonConnected = withDispatch(Button)
*
* // e.g. transform the props using an object as map
* // (unmapped props are passed with the original keys)
* const ButtonConnected = withDispatch(Button, { dispatch: onClick })
*
* // e.g. transform the consumer props
* const ButtonConnected = withDispatch(Button,
* (({ dispatch }) => ({
* onSubmit: value => dispatch(doSomething(value)),
* }))
* )
*
* @param {class} Consumer React context consumer
* @param {string} consumerName name, for debugging purposes
* @return {function} the HOC
*/
export function makeWithConsumer(Consumer, consumerName = 'Consumer') {
function withConsumer(Comp, mapKeysToX = null) {
function ComponentWithConsumer(props) {
return (
<Consumer>
{consumerProps => (
<Comp {...props} {...keysRemapper(consumerProps, mapKeysToX)} />
)}
</Consumer>
)
}
ComponentWithConsumer.displayName = `ComponentWith${consumerName}`
return ComponentWithConsumer
}
withConsumer.displayName = `with${consumerName}`
return withConsumer
}
/**
* Transform the keys of an object.
*
* @param {object} obj the object whose key we want to change
* @param {mapKeysToX} one of
* - an object that maps oldKey: newKey (missing keys are left untouched)
* - a function that gets an object and return a new object
* - null (obj is returned)
*/
function keysRemapper(obj, mapKeysToX = null) {
if (!mapKeysToX) {
return obj
} else if (typeof mapKeysToX === 'function') {
return mapKeysToX(obj)
} else {
const newObj = {
...obj,
}
for (const [oldKey, newKey] of Object.entries(mapKeysToX)) {
delete newObj[oldKey]
newObj[newKey] = obj[oldKey]
}
return newObj
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment