Skip to content

Instantly share code, notes, and snippets.

@hsingh23
Created September 18, 2017 21:32
Show Gist options
  • Save hsingh23/276e6b3dc54c5e363fc06285c71f20a8 to your computer and use it in GitHub Desktop.
Save hsingh23/276e6b3dc54c5e363fc06285c71f20a8 to your computer and use it in GitHub Desktop.
WithStatePropsFactory
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;
});
},
},
});
*/
@hsingh23
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment