react-error-boundary
Advanced tools
Comparing version 2.0.2 to 2.1.0
@@ -10,2 +10,16 @@ 'use strict'; | ||
var changedArray = function (a, b) { | ||
if (a === void 0) { | ||
a = []; | ||
} | ||
if (b === void 0) { | ||
b = []; | ||
} | ||
return a.some(function (item, index) { | ||
return !Object.is(item, b[index]); | ||
}); | ||
}; | ||
var initialState = { | ||
@@ -30,3 +44,5 @@ error: null, | ||
_this.resetErrorBoundary = function () { | ||
return _this.setState(initialState); | ||
_this.props.onReset == null ? void 0 : _this.props.onReset(); | ||
_this.setState(initialState); | ||
}; | ||
@@ -49,2 +65,11 @@ | ||
_proto.componentDidUpdate = function componentDidUpdate(prevProps) { | ||
var error = this.state.error; | ||
var resetKeys = this.props.resetKeys; | ||
if (error !== null && changedArray(prevProps.resetKeys, resetKeys)) { | ||
this.resetErrorBoundary(); | ||
} | ||
}; | ||
_proto.render = function render() { | ||
@@ -51,0 +76,0 @@ var _this$state = this.state, |
import _inheritsLoose from '@babel/runtime/helpers/esm/inheritsLoose'; | ||
import React from 'react'; | ||
var changedArray = function (a, b) { | ||
if (a === void 0) { | ||
a = []; | ||
} | ||
if (b === void 0) { | ||
b = []; | ||
} | ||
return a.some(function (item, index) { | ||
return !Object.is(item, b[index]); | ||
}); | ||
}; | ||
var initialState = { | ||
@@ -23,3 +37,5 @@ error: null, | ||
_this.resetErrorBoundary = function () { | ||
return _this.setState(initialState); | ||
_this.props.onReset == null ? void 0 : _this.props.onReset(); | ||
_this.setState(initialState); | ||
}; | ||
@@ -42,2 +58,11 @@ | ||
_proto.componentDidUpdate = function componentDidUpdate(prevProps) { | ||
var error = this.state.error; | ||
var resetKeys = this.props.resetKeys; | ||
if (error !== null && changedArray(prevProps.resetKeys, resetKeys)) { | ||
this.resetErrorBoundary(); | ||
} | ||
}; | ||
_proto.render = function render() { | ||
@@ -44,0 +69,0 @@ var _this$state = this.state, |
@@ -15,2 +15,16 @@ (function (global, factory) { | ||
var changedArray = function (a, b) { | ||
if (a === void 0) { | ||
a = []; | ||
} | ||
if (b === void 0) { | ||
b = []; | ||
} | ||
return a.some(function (item, index) { | ||
return !Object.is(item, b[index]); | ||
}); | ||
}; | ||
var initialState = { | ||
@@ -35,3 +49,5 @@ error: null, | ||
_this.resetErrorBoundary = function () { | ||
return _this.setState(initialState); | ||
_this.props.onReset == null ? void 0 : _this.props.onReset(); | ||
_this.setState(initialState); | ||
}; | ||
@@ -54,2 +70,11 @@ | ||
_proto.componentDidUpdate = function componentDidUpdate(prevProps) { | ||
var error = this.state.error; | ||
var resetKeys = this.props.resetKeys; | ||
if (error !== null && changedArray(prevProps.resetKeys, resetKeys)) { | ||
this.resetErrorBoundary(); | ||
} | ||
}; | ||
_proto.render = function render() { | ||
@@ -56,0 +81,0 @@ var _this$state = this.state, |
@@ -1,2 +0,2 @@ | ||
!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e((r=r||self).ReactErrorBoundary={},r.React)}(this,(function(r,e){"use strict";e=e&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e;var t={error:null,info:null},o=function(r){var o,n;function a(){for(var e,o=arguments.length,n=new Array(o),a=0;a<o;a++)n[a]=arguments[a];return(e=r.call.apply(r,[this].concat(n))||this).state=t,e.resetErrorBoundary=function(){return e.setState(t)},e}n=r,(o=a).prototype=Object.create(n.prototype),o.prototype.constructor=o,o.__proto__=n;var c=a.prototype;return c.componentDidCatch=function(r,e){var t,o;null==(t=(o=this.props).onError)||t.call(o,r,null==e?void 0:e.componentStack),this.setState({error:r,info:e})},c.render=function(){var r=this.state,t=r.error,o=r.info,n=this.props,a=n.fallbackRender,c=n.FallbackComponent,i=n.fallback;if(null!==t){var l={componentStack:null==o?void 0:o.componentStack,error:t,resetErrorBoundary:this.resetErrorBoundary};if(e.isValidElement(i))return i;if("function"==typeof a)return a(l);if("function"==typeof c)return e.createElement(c,l);throw new Error("react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop")}return this.props.children},a}(e.Component);r.ErrorBoundary=o,r.withErrorBoundary=function(r,t){function n(n){return e.createElement(o,t,e.createElement(r,n))}var a=r.displayName||r.name||"Unknown";return n.displayName="withErrorBoundary("+a+")",n},Object.defineProperty(r,"__esModule",{value:!0})})); | ||
!function(r,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e((r=r||self).ReactErrorBoundary={},r.React)}(this,(function(r,e){"use strict";e=e&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e;var t={error:null,info:null},o=function(r){var o,n;function a(){for(var e,o=arguments.length,n=new Array(o),a=0;a<o;a++)n[a]=arguments[a];return(e=r.call.apply(r,[this].concat(n))||this).state=t,e.resetErrorBoundary=function(){null==e.props.onReset||e.props.onReset(),e.setState(t)},e}n=r,(o=a).prototype=Object.create(n.prototype),o.prototype.constructor=o,o.__proto__=n;var i=a.prototype;return i.componentDidCatch=function(r,e){var t,o;null==(t=(o=this.props).onError)||t.call(o,r,null==e?void 0:e.componentStack),this.setState({error:r,info:e})},i.componentDidUpdate=function(r){var e,t,o=this.state.error,n=this.props.resetKeys;null!==o&&(void 0===(e=r.resetKeys)&&(e=[]),void 0===(t=n)&&(t=[]),e.some((function(r,e){return!Object.is(r,t[e])})))&&this.resetErrorBoundary()},i.render=function(){var r=this.state,t=r.error,o=r.info,n=this.props,a=n.fallbackRender,i=n.FallbackComponent,c=n.fallback;if(null!==t){var l={componentStack:null==o?void 0:o.componentStack,error:t,resetErrorBoundary:this.resetErrorBoundary};if(e.isValidElement(c))return c;if("function"==typeof a)return a(l);if("function"==typeof i)return e.createElement(i,l);throw new Error("react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop")}return this.props.children},a}(e.Component);r.ErrorBoundary=o,r.withErrorBoundary=function(r,t){function n(n){return e.createElement(o,t,e.createElement(r,n))}var a=r.displayName||r.name||"Unknown";return n.displayName="withErrorBoundary("+a+")",n},Object.defineProperty(r,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=react-error-boundary.umd.min.js.map |
{ | ||
"name": "react-error-boundary", | ||
"version": "2.0.2", | ||
"version": "2.1.0", | ||
"description": "Simple reusable React error boundary component", | ||
@@ -5,0 +5,0 @@ "main": "dist/react-error-boundary.cjs.js", |
137
README.md
@@ -39,3 +39,11 @@ <div align="center"> | ||
- [Error Recovery](#error-recovery) | ||
- [fallback prop](#fallback-prop) | ||
- [API](#api) | ||
- [`ErrorBoundary` props](#errorboundary-props) | ||
- [`children`](#children) | ||
- [`FallbackComponent`](#fallbackcomponent) | ||
- [`fallbackRender`](#fallbackrender) | ||
- [`fallback`](#fallback) | ||
- [`onError`](#onerror) | ||
- [`onReset`](#onreset) | ||
- [`resetKeys`](#resetkeys) | ||
- [Issues](#issues) | ||
@@ -64,5 +72,5 @@ - [๐ Bugs](#-bugs) | ||
```jsx | ||
import ErrorBoundary from 'react-error-boundary' | ||
import {ErrorBoundary} from 'react-error-boundary' | ||
function ErrorFallback({error, componentStack}) { | ||
function ErrorFallback({error, componentStack, resetErrorBoundary}) { | ||
return ( | ||
@@ -73,2 +81,3 @@ <div role="alert"> | ||
<pre>{componentStack}</pre> | ||
<button onClick={resetErrorBoundary}>Try again</button> | ||
</div> | ||
@@ -79,5 +88,10 @@ ) | ||
const ui = ( | ||
<ErrorBoundary FallbackComponent={ErrorFallback}> | ||
<ErrorBoundary | ||
FallbackComponent={ErrorFallback} | ||
onReset={() => { | ||
// reset the state of your app so the error doesn't happen again | ||
}} | ||
> | ||
<ComponentThatMayError /> | ||
</ErrorBoundary>, | ||
</ErrorBoundary> | ||
) | ||
@@ -89,3 +103,3 @@ ``` | ||
```jsx | ||
import ErrorBoundary from 'react-error-boundary' | ||
import {ErrorBoundary} from 'react-error-boundary' | ||
@@ -123,11 +137,14 @@ const myErrorHandler = (error: Error, componentStack: string) => { | ||
Often you may want to recover from the error. You can do this using the | ||
`resetErrorBoundary` prop: | ||
In the event of an error if you want to recover from that error and allow the | ||
user to "try again" or continue with their work, you'll need a way to reset the | ||
ErrorBoundary's internal state. You can do this various ways, but here's the | ||
most idiomatic approach: | ||
```jsx | ||
function ErrorFallback({error, resetErrorBoundary}) { | ||
function ErrorFallback({error, componentStack, resetErrorBoundary}) { | ||
return ( | ||
<div role="alert"> | ||
<div>Oh no</div> | ||
<p>Something went wrong:</p> | ||
<pre>{error.message}</pre> | ||
<pre>{componentStack}</pre> | ||
<button onClick={resetErrorBoundary}>Try again</button> | ||
@@ -137,11 +154,70 @@ </div> | ||
} | ||
function Bomb() { | ||
throw new Error('๐ฅ CABOOM ๐ฅ') | ||
} | ||
function App() { | ||
const [explode, setExplode] = React.useState(false) | ||
return ( | ||
<div> | ||
<button onClick={() => setExplode(e => !e)}>toggle explode</button> | ||
<ErrorBoundary | ||
FallbackComponent={ErrorFallback} | ||
onReset={() => setExplode(false)} | ||
resetKeys={[explode]} | ||
> | ||
{explode ? <Bomb /> : null} | ||
</ErrorBoundary> | ||
</div> | ||
) | ||
} | ||
``` | ||
However, normally "trying again" like that will just result in the user | ||
experiencing the same error. Typically some other state in your app will need to | ||
be reset as well. The problem is, the `ErrorFallback` component won't usually | ||
have access to the state that needs to be reset. | ||
So, with this setup, you've got a button which when clicked will trigger an | ||
error. Clicking the button again will trigger a re-render which recovers from | ||
the error (we no longer render the `<Bomb />`). We also pass the `resetKeys` | ||
prop which is an array of elements for the `ErrorBoundary` to check each render | ||
(if there's currently an error state). If any of those elements change between | ||
renders, then the `ErrorBoundary` will reset the state which will re-render the | ||
children. | ||
So alternatively, you can use the `fallbackRender` prop: | ||
We have the `onReset` prop so that if the user clicks the "Try again" button we | ||
have an opportunity to re-initialize our state into a good place before | ||
attempting to re-render the children. | ||
This combination allows us both the opportunity to give the user something | ||
specific to do to recover from the error, and recover from the error by | ||
interacting with other areas of the app that might fix things for us. It's hard | ||
to describe here, but hopefully it makes sense when you apply it to your | ||
specific scenario. | ||
## API | ||
### `ErrorBoundary` props | ||
### `children` | ||
This is what you want rendered when everything's working fine. If there's an | ||
error that React can handle within the children of the `ErrorBoundary`, the | ||
`ErrorBoundary` will catch that and allow you to handle it gracefully. | ||
### `FallbackComponent` | ||
This is a component you want rendered in the event of an error. As props it will | ||
be passed the `error`, `componentStack`, and `resetErrorBoundary` (which will | ||
reset the error boundary's state when called, useful for a "try again" button | ||
when used in combination with the `onReset` prop). | ||
This is required if no `fallback` or `fallbackRender` prop is provided. | ||
### `fallbackRender` | ||
This is a render-prop based API that allows you to inline your error fallback UI | ||
into the component that's using the `ErrorBoundary`. This is useful if you need | ||
access to something that's in the scope of the component you're using. | ||
It will be called with an object that has `error`, `componentStack`, and | ||
`resetErrorBoundary`: | ||
```jsx | ||
@@ -156,3 +232,6 @@ const ui = ( | ||
onClick={() => { | ||
resetComponentState() // <-- this is why the fallbackRender is useful | ||
// this next line is why the fallbackRender is useful | ||
resetComponentState() | ||
// though you could accomplish this with a combination | ||
// of the FallbackCallback and onReset props as well. | ||
resetErrorBoundary() | ||
@@ -176,4 +255,6 @@ }} | ||
### fallback prop | ||
This is required if no `FallbackComponent` or `fallback` prop is provided. | ||
### `fallback` | ||
In the spirit of consistency with the `React.Suspense` component, we also | ||
@@ -192,2 +273,24 @@ support a simple `fallback` prop which you can use for a generic fallback. This | ||
### `onError` | ||
This will be called when there's been an error that the `ErrorBoundary` has | ||
handled. It will be called with two arguments: `error`, `componentStack`. | ||
### `onReset` | ||
This will be called immediately before the `ErrorBoundary` resets it's internal | ||
state (which will result in rendering the `children` again). You should use this | ||
to ensure that re-rendering the children will not result in a repeat of the same | ||
error happening again. | ||
### `resetKeys` | ||
Sometimes an error happens as a result of local state to the component that's | ||
rendering the error. If this is the case, then you can pass `resetKeys` which is | ||
an array of values. If the `ErrorBoundary` is in an error state, then it will | ||
check these values each render and if they change from one render to the next, | ||
then it will reset automatically (triggering a re-render of the `children`). | ||
See the recovery examples above. | ||
## Issues | ||
@@ -194,0 +297,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
35426
281
329