Created
September 18, 2017 21:32
-
-
Save hsingh23/276e6b3dc54c5e363fc06285c71f20a8 to your computer and use it in GitHub Desktop.
WithStatePropsFactory
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 { reduce, isFunction, forEach } from 'lodash'; | |
import React, { PureComponent } from 'react'; | |
/** | |
* WithStatePropsFactory is a Higher Order Function that returns a Higher Order Component https://facebook.github.io/react/docs/higher-order-components.html | |
* It is similar to withStateHandlers from recompose https://github.com/acdlite/recompose/blob/master/docs/API.md#withstatehandlers but more versitile b/c it handles https://github.com/acdlite/recompose/issues/443 | |
* It can be used to pass in data from async functions to WrappedComponent as props making them easier to test | |
* initialState | |
* @param {Object} initialState - the initialState of the HOC | |
* @param {Object} lifecycle - lifecycle functions that wont be passed down to the WrappedComponent but will be evaluated in context | |
* @param {Object} additionalProps - additonal key value pairs to pass to the WrappedComponent, If the value is a function, this will be bound to the Component so you can call this.setState. If you pass an anonymous function, this will not be bound, however you can still access it via that which is defined in a closure wrapping your function | |
*/ | |
const WithStatePropsFactory = ({ initialState, additionalProps, lifecycle }) => WrappedComponent => class extends PureComponent { | |
constructor(props) { | |
super(props); | |
this.state = initialState; | |
forEach(lifecycle, (v, k) => { | |
// eslint-disable-next-line | |
this[k] = (that => v.bind(this))(this); | |
}); | |
this.additionalProps = reduce(additionalProps, (memo, val, key) => { | |
// eslint-disable-next-line | |
memo[key] = isFunction(val) ? (that => val.bind(this))(this) : val; | |
return memo; | |
}, {}); | |
} | |
render() { | |
return (<WrappedComponent | |
{...this.state} | |
{...this.additionalProps} | |
{...this.props} | |
/>); | |
} | |
}; | |
export default WithStatePropsFactory; | |
/** | |
* Example: | |
* const enhancer = WithStatePropsFactory({ initialState: { results: [], loading: false }, | |
additionalProps: { | |
fetchStuff({ page }) { | |
this.setState({ loading: true }); | |
window.fetch(`url`) | |
.then(apiResponse => apiResponse.json()) | |
.then(purchasesTransformer) | |
.then((data) => { | |
this.setState({ ...data }); | |
}) | |
.catch((e) => { | |
console.error('Unable to get purchases: ', e, document.cookie); | |
return undefined; | |
}); | |
}, | |
}, | |
}); | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I haven't tried the lifecycle stuff yet and the display name doesn't work well. Going to figure that out before making this a library