Skip to content

Instantly share code, notes, and snippets.

@janv
Last active July 31, 2018 13:41
Show Gist options
  • Save janv/427631f9d60e40dcfbd990a757642916 to your computer and use it in GitHub Desktop.
Save janv/427631f9d60e40dcfbd990a757642916 to your computer and use it in GitHub Desktop.
import React from 'react';
/**
* Use this to pass resource objects from Angular to React
*
* Usage:
* ```
* <ResourceObserver resource={someResource}>
* {(r) => <SomeComponent myProp={r}/>}
* </ResourceObserver>
* ```
*
* This is necessary because Angular resources are objects that are modified in place.
* This pattern doesn't play along well with React. This component takes in-flight
* resource and observes it for changes, passing new props to the target component
* when something changes.
*
*/
export class ResourceObserver extends React.Component {
isMounted = false;
state = { resource: null };
constructor(props) {
super(props);
this.manage(props.resource);
}
componentDidUpdate(prevProps) {
if (prevProps.resource !== this.props.resource) {
this.manage(this.props.resource);
}
}
manage(resource) {
if (typeof resource !== 'object') return;
const { $resolved, $promise, ...rest } = resource;
if (this.isMounted) {
this.setState({ resource: rest });
} else {
this.state = { resource: rest }; // eslint-disable-line react/no-direct-mutation-state
}
if (!$resolved) {
$promise.then(() => {
if (this.isMounted && resource === this.props.resource) {
this.manage(resource);
}
});
}
}
componentDidMount() {
this.isMounted = true;
}
componentWillUnmount() {
this.isMounted = false;
}
render() {
return this.props.children(this.state.resource);
}
}
export default function withResource(propName) {
return function decorate(Component) {
return props => (
<ResourceObserver resource={props[propName]}>
{r => {
const resourceProp = { [propName]: r };
return <Component {...props} {...resourceProp} />;
}}
</ResourceObserver>
);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment