Last active
July 1, 2016 06:17
-
-
Save pl12133/93cf009b330cfb35e77efe66ec025371 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/* 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