Skip to content

Instantly share code, notes, and snippets.

@pl12133
Last active July 1, 2016 06:17
Show Gist options
  • Save pl12133/93cf009b330cfb35e77efe66ec025371 to your computer and use it in GitHub Desktop.
Save pl12133/93cf009b330cfb35e77efe66ec025371 to your computer and use it in GitHub Desktop.
/* A collection of React higher order components I have been working on */
// <If>, the simplest of HOCs, to conditionally render it's children
// Accepts a `test`, if `test === true`, then render the children; else render nothing
function If ({children, test}) {
return Boolean(test)
? children
: null
}
If.propTypes = {
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element)
]).isRequired,
test: PropTypes.any
};
// <If> example:
// render a component if `this.state.hover === true`
<If test={this.state.hover}>
<HoveringComponent />
</If>
/* ======== */
// <PropInjector>, a wrapper of `React.cloneElement`
// It injects it's props into all it's children
function PropInjector ({children, ...props}) {
return Array.isArray(children)
? children.map((child) => React.cloneElement(child, props))
: React.cloneElement(React.Children.only(children), props);
};
PropInjector.propTypes = {
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element)
]).isRequired
};
// <PropInjector> example:
// Creating 3 `div` elements with the `style={ { width: '100%' } }` prop
<PropInjector style={ { width: '100%' } } />
<div />
<div />
<div />
</PropInjector>
/* ======== */
// <TryRender> takes a Component and attempts to render it in a try/catch block
// If the render does not throw, then that Instance is returned; else errComponent is returned
// <DefaultError> is the default Component to show on error:
const DefaultError = ({name}) => (
<span><strong>{'!! ' + name + ': '}</strong>{'An error has occured'}</span>
);
function TryRender ({
children: WrappedComponent,
errback,
errComponent = <DefaultError name={WrappedComponent.name} />,
childProps = {}
}) {
let renderedElement;
try {
if (WrappedComponent.prototype.render) {
console.log('Class Passed In');
renderedElement = (new WrappedComponent(childProps)).render();
} else {
console.log('Function Passed In');
renderedElement = new WrappedComponent(childProps);
}
} catch (e) {
renderedElement = false;
errback && errback(WrappedComponent.name + ' threw: ' + e);
}
return renderedElement || errComponent;
}
TryRender.propTypes = {
children: PropTypes.func.isRequired,
errback: PropTypes.func,
errComponent: React.PropTypes.element,
childProps: PropTypes.object
};
// <TryRender> example:
// <ErrorComponent> is a component that always throws an error.
function ErrorComponent (props) {
throw new Error('Error error');
return (
<span>{'Error'}</span>
);
}
// By wrapping the component with <TryRender> it will render the <DefaultError> component instead of crashing.
function App (props) {
return (
<TryRender>
{ErrorComponent}
</TryRender>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment