UNPKG

@react-nitro/error-boundary

Version:

An Error Boundary HOC for React Projects

88 lines (87 loc) 2.89 kB
import React from 'react'; import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment'; import { get } from './utils/lodashUtils'; import Storage from './utils/storageManager'; const errorSessionKey = 'error_debug'; /** * Function to create the HOC to act as an error boundary * @param {Object} WrappedComponent The React component to be wrapped by the HOC. * @param {String} path The path(s) of the properties to test from `this.props`. * @param {[String]} name The name of the component to be shown in the error. */ const withErrorBoundary = (WrappedComponent, path, name) => class extends React.Component { constructor(props) { super(props); this.state = { hasError: false, debugPaths: [], error: null, info: null }; this.name = name || 'Not Specified'; this.debug = Storage.getSessionStorage(errorSessionKey) || false; } componentDidCatch(error, info) { const debugPaths = this.validatePath(this.props); // Display fallback UI this.setState({ hasError: true, error, info, debugPaths }); } /** * Function to render the error in-place for the component * replacing the original wrapped component. */ getErrors() { return ( <div style={{ borderRadius: '3px', background: '#ff3860', color: '#FFF', fontFamily: '"Lucida Console", "Courier New", monospace', padding: '10px', margin: '10px', fontSize: '12px' }} > <i>Component</i>:{this.name} <br /> <i>Error</i>: {this.state.error.toString()} <br /> <i>Info</i>: {JSON.stringify(this.state.info)} <br /> <i>Paths</i>: {this.state.debugPaths.length ? this.state.debugPaths.map(dp => `'${dp.path}' `) : 'none'} </div> ); } /** * Function to validate the paths on the props object * and show error when paths return undefined. * @param {Object} props The component props */ validatePath(props) { if (!path || !props) { return []; } const errorPaths = []; if (Array.isArray(path) && path.length > 0) { path.forEach(p => { const result = get(props, p); if (!result) { errorPaths.push({ path: p }); } }); } else if (path && typeof path === 'string') { const result = get(props, path); if (!result) { errorPaths.push({ path }); } } return errorPaths; } render() { if (this.state.hasError && this.debug) { // You can render any custom fallback UI if (ExecutionEnvironment.canUseDOM) { return this.getErrors(); } } return <WrappedComponent {...this.props} />; } }; export { get, Storage, withErrorBoundary };