react-error-boundary 6.0.0 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -164
- package/dist/react-error-boundary.cjs +2 -0
- package/dist/react-error-boundary.cjs.map +1 -0
- package/dist/react-error-boundary.d.ts +165 -2
- package/dist/react-error-boundary.js +92 -132
- package/dist/react-error-boundary.js.map +1 -0
- package/package.json +106 -62
- package/dist/declarations/src/ErrorBoundary.d.ts +0 -21
- package/dist/declarations/src/ErrorBoundaryContext.d.ts +0 -6
- package/dist/declarations/src/index.d.ts +0 -5
- package/dist/declarations/src/types.d.ts +0 -34
- package/dist/declarations/src/useErrorBoundary.d.ts +0 -5
- package/dist/declarations/src/withErrorBoundary.d.ts +0 -3
- package/dist/react-error-boundary.development.js +0 -154
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
<img src="https://react-error-boundary-lib.vercel.app/og.svg" alt="react-error-boundary logo" width="400" height="210" />
|
|
2
2
|
|
|
3
|
-
Reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component. Supports all React renderers (including React DOM and React Native).
|
|
3
|
+
`react-error-boundary`: Reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component. Supports all React renderers (including React DOM and React Native).
|
|
4
4
|
|
|
5
5
|
### If you like this project, 🎉 [become a sponsor](https://github.com/sponsors/bvaughn/) or ☕ [buy me a coffee](http://givebrian.coffee/)
|
|
6
6
|
|
|
@@ -17,171 +17,93 @@ pnpm add react-error-boundary
|
|
|
17
17
|
yarn add react-error-boundary
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
##
|
|
21
|
-
|
|
22
|
-
### `ErrorBoundary` component
|
|
23
|
-
Wrap an `ErrorBoundary` component around other React components to "catch" errors and render a fallback UI. The component supports several ways to render a fallback (as shown below).
|
|
24
|
-
|
|
25
|
-
> **Note** `ErrorBoundary` is a _client_ component. You can only pass props to it that are serializeable or use it in files that have a `"use client";` directive.
|
|
26
|
-
|
|
27
|
-
#### `ErrorBoundary` with `fallback` prop
|
|
28
|
-
The simplest way to render a default "something went wrong" type of error message.
|
|
29
|
-
```js
|
|
30
|
-
"use client";
|
|
31
|
-
|
|
32
|
-
import { ErrorBoundary } from "react-error-boundary";
|
|
33
|
-
|
|
34
|
-
<ErrorBoundary fallback={<div>Something went wrong</div>}>
|
|
35
|
-
<ExampleApplication />
|
|
36
|
-
</ErrorBoundary>
|
|
37
|
-
```
|
|
38
|
-
#### `ErrorBoundary` with `fallbackRender` prop
|
|
39
|
-
["Render prop"](https://react.dev/reference/react/Children#calling-a-render-prop-to-customize-rendering) function responsible for returning a fallback UI based on a thrown value.
|
|
40
|
-
```js
|
|
41
|
-
"use client";
|
|
42
|
-
|
|
43
|
-
import { ErrorBoundary } from "react-error-boundary";
|
|
44
|
-
|
|
45
|
-
function fallbackRender({ error, resetErrorBoundary }) {
|
|
46
|
-
// Call resetErrorBoundary() to reset the error boundary and retry the render.
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<div role="alert">
|
|
50
|
-
<p>Something went wrong:</p>
|
|
51
|
-
<pre style={{ color: "red" }}>{error.message}</pre>
|
|
52
|
-
</div>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
<ErrorBoundary
|
|
57
|
-
fallbackRender={fallbackRender}
|
|
58
|
-
onReset={(details) => {
|
|
59
|
-
// Reset the state of your app so the error doesn't happen again
|
|
60
|
-
}}
|
|
61
|
-
>
|
|
62
|
-
<ExampleApplication />
|
|
63
|
-
</ErrorBoundary>;
|
|
64
|
-
```
|
|
65
|
-
#### `ErrorBoundary` with `FallbackComponent` prop
|
|
66
|
-
React component responsible for returning a fallback UI based on a thrown value.
|
|
67
|
-
```js
|
|
68
|
-
"use client";
|
|
69
|
-
|
|
70
|
-
import { ErrorBoundary } from "react-error-boundary";
|
|
71
|
-
|
|
72
|
-
function Fallback({ error, resetErrorBoundary }) {
|
|
73
|
-
// Call resetErrorBoundary() to reset the error boundary and retry the render.
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<div role="alert">
|
|
77
|
-
<p>Something went wrong:</p>
|
|
78
|
-
<pre style={{ color: "red" }}>{error.message}</pre>
|
|
79
|
-
</div>
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
<ErrorBoundary
|
|
84
|
-
FallbackComponent={Fallback}
|
|
85
|
-
onReset={(details) => {
|
|
86
|
-
// Reset the state of your app so the error doesn't happen again
|
|
87
|
-
}}
|
|
88
|
-
>
|
|
89
|
-
<ExampleApplication />
|
|
90
|
-
</ErrorBoundary>;
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
#### Logging errors with `onError`
|
|
94
|
-
|
|
95
|
-
```js
|
|
96
|
-
"use client";
|
|
97
|
-
|
|
98
|
-
import { ErrorBoundary } from "react-error-boundary";
|
|
99
|
-
|
|
100
|
-
const logError = (error: Error, info: { componentStack: string }) => {
|
|
101
|
-
// Do something with the error, e.g. log to an external API
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const ui = (
|
|
105
|
-
<ErrorBoundary FallbackComponent={ErrorFallback} onError={logError}>
|
|
106
|
-
<ExampleApplication />
|
|
107
|
-
</ErrorBoundary>
|
|
108
|
-
);
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### `useErrorBoundary` hook
|
|
112
|
-
Convenience hook for imperatively showing or dismissing error boundaries.
|
|
113
|
-
|
|
114
|
-
#### Show the nearest error boundary from an event handler
|
|
115
|
-
|
|
116
|
-
React only handles errors thrown during render or during component lifecycle methods (e.g. effects and did-mount/did-update). Errors thrown in event handlers, or after async code has run, will not be caught.
|
|
20
|
+
## FAQs
|
|
117
21
|
|
|
118
|
-
|
|
22
|
+
Frequently asked questions can be found [here](https://react-error-boundary-lib.vercel.app/common-questions).
|
|
119
23
|
|
|
120
|
-
|
|
121
|
-
"use client";
|
|
122
|
-
|
|
123
|
-
import { useErrorBoundary } from "react-error-boundary";
|
|
124
|
-
|
|
125
|
-
function Example() {
|
|
126
|
-
const { showBoundary } = useErrorBoundary();
|
|
127
|
-
|
|
128
|
-
useEffect(() => {
|
|
129
|
-
fetchGreeting(name).then(
|
|
130
|
-
response => {
|
|
131
|
-
// Set data in state and re-render
|
|
132
|
-
},
|
|
133
|
-
error => {
|
|
134
|
-
// Show error boundary
|
|
135
|
-
showBoundary(error);
|
|
136
|
-
}
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Render ...
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
#### Dismiss the nearest error boundary
|
|
145
|
-
A fallback component can use this hook to request the nearest error boundary retry the render that originally failed.
|
|
146
|
-
|
|
147
|
-
```js
|
|
148
|
-
"use client";
|
|
149
|
-
|
|
150
|
-
import { useErrorBoundary } from "react-error-boundary";
|
|
151
|
-
|
|
152
|
-
function ErrorFallback({ error }) {
|
|
153
|
-
const { resetBoundary } = useErrorBoundary();
|
|
154
|
-
|
|
155
|
-
return (
|
|
156
|
-
<div role="alert">
|
|
157
|
-
<p>Something went wrong:</p>
|
|
158
|
-
<pre style={{ color: "red" }}>{error.message}</pre>
|
|
159
|
-
<button onClick={resetBoundary}>Try again</button>
|
|
160
|
-
</div>
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### `withErrorBoundary` HOC
|
|
166
|
-
This package can also be used as a [higher-order component](https://legacy.reactjs.org/docs/higher-order-components.html) that accepts all of the same props as above:
|
|
167
|
-
|
|
168
|
-
```js
|
|
169
|
-
"use client";
|
|
170
|
-
|
|
171
|
-
import {withErrorBoundary} from 'react-error-boundary'
|
|
172
|
-
|
|
173
|
-
const ComponentWithErrorBoundary = withErrorBoundary(ExampleComponent, {
|
|
174
|
-
fallback: <div>Something went wrong</div>,
|
|
175
|
-
onError(error, info) {
|
|
176
|
-
// Do something with the error
|
|
177
|
-
// E.g. log to an error logging client here
|
|
178
|
-
},
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
// Can be rendered as <ComponentWithErrorBoundary {...props} />
|
|
182
|
-
```
|
|
24
|
+
## API
|
|
183
25
|
|
|
184
|
-
|
|
26
|
+
### ErrorBoundary
|
|
27
|
+
|
|
28
|
+
<!-- ErrorBoundary:description:begin -->
|
|
29
|
+
A reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component.
|
|
30
|
+
Wrap this component around other React components to "catch" errors and render a fallback UI.
|
|
31
|
+
|
|
32
|
+
This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),
|
|
33
|
+
so it has all of the advantages and constraints of that API.
|
|
34
|
+
This means that it can't catch errors during:
|
|
35
|
+
- Server side rendering</li>
|
|
36
|
+
- Event handlers
|
|
37
|
+
- Asynchronous code (including effects)
|
|
38
|
+
|
|
39
|
+
ℹ️ The component provides several ways to render a fallback: `fallback`, `fallbackRender`, and `FallbackComponent`.
|
|
40
|
+
Refer to the documentation to determine which is best for your application.
|
|
41
|
+
|
|
42
|
+
ℹ️ This is a **client component**. You can only pass props to it that are serializeable or use it in files that have a `"use client";` directive.
|
|
43
|
+
<!-- ErrorBoundary:description:end -->
|
|
44
|
+
|
|
45
|
+
#### Required props
|
|
46
|
+
|
|
47
|
+
<!-- ErrorBoundary:required-props:begin -->
|
|
48
|
+
None
|
|
49
|
+
<!-- ErrorBoundary:required-props:end -->
|
|
50
|
+
|
|
51
|
+
#### Optional props
|
|
52
|
+
|
|
53
|
+
<!-- ErrorBoundary:optional-props:begin -->
|
|
54
|
+
|
|
55
|
+
<table>
|
|
56
|
+
<thead>
|
|
57
|
+
<tr>
|
|
58
|
+
<th>Name</th>
|
|
59
|
+
<th>Description</th>
|
|
60
|
+
</tr>
|
|
61
|
+
</thead>
|
|
62
|
+
<tbody>
|
|
63
|
+
<tr>
|
|
64
|
+
<td>onError</td>
|
|
65
|
+
<td><p>Optional callback to enable e.g. logging error information to a server.
|
|
66
|
+
@param error Error that was thrown
|
|
67
|
+
@param info React "component stack" identifying where the error was thrown</p>
|
|
68
|
+
</td>
|
|
69
|
+
</tr>
|
|
70
|
+
<tr>
|
|
71
|
+
<td>onReset</td>
|
|
72
|
+
<td><p>Optional callback to to be notified when an error boundary is "reset" so React can retry the failed render.</p>
|
|
73
|
+
</td>
|
|
74
|
+
</tr>
|
|
75
|
+
<tr>
|
|
76
|
+
<td>resetKeys</td>
|
|
77
|
+
<td><p>When changed, these keys will reset a triggered error boundary.
|
|
78
|
+
This can be useful when an error condition may be tied to some specific state (that can be uniquely identified by key).
|
|
79
|
+
See the the documentation for examples of how to use this prop.</p>
|
|
80
|
+
</td>
|
|
81
|
+
</tr>
|
|
82
|
+
<tr>
|
|
83
|
+
<td>fallback</td>
|
|
84
|
+
<td><p>Static content to render in place of an error if one is thrown.</p>
|
|
85
|
+
<pre><code class="language-tsx"><ErrorBoundary fallback={<div class="text-red">Something went wrong</div>} />
|
|
86
|
+
</code></pre>
|
|
87
|
+
</td>
|
|
88
|
+
</tr>
|
|
89
|
+
<tr>
|
|
90
|
+
<td>FallbackComponent</td>
|
|
91
|
+
<td><p>React component responsible for returning a fallback UI based on a thrown value.</p>
|
|
92
|
+
<pre><code class="language-tsx"><ErrorBoundary FallbackComponent={Fallback} />
|
|
93
|
+
</code></pre>
|
|
94
|
+
</td>
|
|
95
|
+
</tr>
|
|
96
|
+
<tr>
|
|
97
|
+
<td>fallbackRender</td>
|
|
98
|
+
<td><p><a href="https://react.dev/reference/react/Children#calling-a-render-prop-to-customize-rendering">Render prop</a> function responsible for returning a fallback UI based on a thrown value.</p>
|
|
99
|
+
<pre><code class="language-tsx"><ErrorBoundary fallbackRender={({ error, resetErrorBoundary }) => <div>...</div>} />
|
|
100
|
+
</code></pre>
|
|
101
|
+
</td>
|
|
102
|
+
</tr>
|
|
103
|
+
</tbody>
|
|
104
|
+
</table>
|
|
105
|
+
|
|
106
|
+
<!-- ErrorBoundary:optional-props:end -->
|
|
185
107
|
|
|
186
108
|
# FAQ
|
|
187
109
|
## `ErrorBoundary` cannot be used as a JSX component
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react"),c=s.createContext(null),u={didCatch:!1,error:null};class l extends s.Component{constructor(e){super(e),this.resetErrorBoundary=this.resetErrorBoundary.bind(this),this.state=u}static getDerivedStateFromError(e){return{didCatch:!0,error:e}}resetErrorBoundary(...e){const{error:t}=this.state;t!==null&&(this.props.onReset?.({args:e,reason:"imperative-api"}),this.setState(u))}componentDidCatch(e,t){this.props.onError?.(e,t)}componentDidUpdate(e,t){const{didCatch:o}=this.state,{resetKeys:n}=this.props;o&&t.error!==null&&y(e.resetKeys,n)&&(this.props.onReset?.({next:n,prev:e.resetKeys,reason:"keys"}),this.setState(u))}render(){const{children:e,fallbackRender:t,FallbackComponent:o,fallback:n}=this.props,{didCatch:a,error:i}=this.state;let d=e;if(a){const h={error:i,resetErrorBoundary:this.resetErrorBoundary};if(typeof t=="function")d=t(h);else if(o)d=s.createElement(o,h);else if(n!==void 0)d=n;else throw i}return s.createElement(c.Provider,{value:{didCatch:a,error:i,resetErrorBoundary:this.resetErrorBoundary}},d)}}function y(r=[],e=[]){return r.length!==e.length||r.some((t,o)=>!Object.is(t,e[o]))}function E(r){return r!==null&&typeof r=="object"&&"didCatch"in r&&typeof r.didCatch=="boolean"&&"error"in r&&"resetErrorBoundary"in r&&typeof r.resetErrorBoundary=="function"}function f(r){if(!E(r))throw new Error("ErrorBoundaryContext not found")}function p(){const r=s.useContext(c);f(r);const{error:e,resetErrorBoundary:t}=r,[o,n]=s.useState({error:null,hasError:!1}),a=s.useMemo(()=>({error:e,resetBoundary:()=>{t(),n({error:null,hasError:!1})},showBoundary:i=>n({error:i,hasError:!0})}),[e,t]);if(o.hasError)throw o.error;return a}function B(r,e){const t=s.forwardRef((n,a)=>s.createElement(l,e,s.createElement(r,{...n,ref:a}))),o=r.displayName||r.name||"Unknown";return t.displayName=`withErrorBoundary(${o})`,t}exports.ErrorBoundary=l;exports.ErrorBoundaryContext=c;exports.useErrorBoundary=p;exports.withErrorBoundary=B;
|
|
2
|
+
//# sourceMappingURL=react-error-boundary.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-error-boundary.cjs","sources":["../lib/context/ErrorBoundaryContext.ts","../lib/components/ErrorBoundary.tsx","../lib/utils/isErrorBoundaryContext.ts","../lib/utils/assertErrorBoundaryContext.ts","../lib/hooks/useErrorBoundary.ts","../lib/utils/withErrorBoundary.ts"],"sourcesContent":["import { createContext } from \"react\";\n\nexport type ErrorBoundaryContextType = {\n didCatch: boolean;\n error: Error | null;\n resetErrorBoundary: (...args: unknown[]) => void;\n};\n\nexport const ErrorBoundaryContext =\n createContext<ErrorBoundaryContextType | null>(null);\n","import { Component, createElement, type ErrorInfo } from \"react\";\nimport { ErrorBoundaryContext } from \"../context/ErrorBoundaryContext\";\nimport type { ErrorBoundaryProps, FallbackProps } from \"../types\";\n\nconst isDevelopment = import.meta.env.DEV;\n\ntype ErrorBoundaryState =\n | {\n didCatch: true;\n error: Error;\n }\n | {\n didCatch: false;\n error: null;\n };\n\nconst initialState: ErrorBoundaryState = {\n didCatch: false,\n error: null,\n};\n\n/**\n * A reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component.\n * Wrap this component around other React components to \"catch\" errors and render a fallback UI.\n *\n * This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),\n * so it has all of the advantages and constraints of that API.\n * This means that it can't catch errors during:\n * - Server side rendering</li>\n * - Event handlers\n * - Asynchronous code (including effects)\n *\n * ℹ️ The component provides several ways to render a fallback: `fallback`, `fallbackRender`, and `FallbackComponent`.\n * Refer to the documentation to determine which is best for your application.\n *\n * ℹ️ This is a **client component**. You can only pass props to it that are serializeable or use it in files that have a `\"use client\";` directive.\n */\nexport class ErrorBoundary extends Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n\n this.resetErrorBoundary = this.resetErrorBoundary.bind(this);\n this.state = initialState;\n }\n\n static getDerivedStateFromError(error: Error) {\n return { didCatch: true, error };\n }\n\n resetErrorBoundary(...args: unknown[]) {\n const { error } = this.state;\n\n if (error !== null) {\n this.props.onReset?.({\n args,\n reason: \"imperative-api\",\n });\n\n this.setState(initialState);\n }\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n this.props.onError?.(error, info);\n }\n\n componentDidUpdate(\n prevProps: ErrorBoundaryProps,\n prevState: ErrorBoundaryState,\n ) {\n const { didCatch } = this.state;\n const { resetKeys } = this.props;\n\n // There's an edge case where if the thing that triggered the error happens to *also* be in the resetKeys array,\n // we'd end up resetting the error boundary immediately.\n // This would likely trigger a second error to be thrown.\n // So we make sure that we don't check the resetKeys on the first call of cDU after the error is set.\n\n if (\n didCatch &&\n prevState.error !== null &&\n hasArrayChanged(prevProps.resetKeys, resetKeys)\n ) {\n this.props.onReset?.({\n next: resetKeys,\n prev: prevProps.resetKeys,\n reason: \"keys\",\n });\n\n this.setState(initialState);\n }\n }\n\n render() {\n const { children, fallbackRender, FallbackComponent, fallback } =\n this.props;\n const { didCatch, error } = this.state;\n\n let childToRender = children;\n\n if (didCatch) {\n const props: FallbackProps = {\n error,\n resetErrorBoundary: this.resetErrorBoundary,\n };\n\n if (typeof fallbackRender === \"function\") {\n childToRender = fallbackRender(props);\n } else if (FallbackComponent) {\n childToRender = createElement(FallbackComponent, props);\n } else if (fallback !== undefined) {\n childToRender = fallback;\n } else {\n if (isDevelopment) {\n console.error(\n \"react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop\",\n );\n }\n\n throw error;\n }\n }\n\n return createElement(\n ErrorBoundaryContext.Provider,\n {\n value: {\n didCatch,\n error,\n resetErrorBoundary: this.resetErrorBoundary,\n },\n },\n childToRender,\n );\n }\n}\n\nfunction hasArrayChanged(a: unknown[] = [], b: unknown[] = []) {\n return (\n a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]))\n );\n}\n","import type { ErrorBoundaryContextType } from \"../context/ErrorBoundaryContext\";\n\nexport function isErrorBoundaryContext(\n value: unknown,\n): value is ErrorBoundaryContextType {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"didCatch\" in value &&\n typeof value.didCatch === \"boolean\" &&\n \"error\" in value &&\n \"resetErrorBoundary\" in value &&\n typeof value.resetErrorBoundary === \"function\"\n );\n}\n","import type { ErrorBoundaryContextType } from \"../context/ErrorBoundaryContext\";\nimport { isErrorBoundaryContext } from \"./isErrorBoundaryContext\";\n\nexport function assertErrorBoundaryContext(\n value: unknown,\n): asserts value is ErrorBoundaryContextType {\n if (!isErrorBoundaryContext(value)) {\n throw new Error(\"ErrorBoundaryContext not found\");\n }\n}\n","import { useContext, useMemo, useState } from \"react\";\nimport { ErrorBoundaryContext } from \"../context/ErrorBoundaryContext\";\nimport { assertErrorBoundaryContext } from \"../utils/assertErrorBoundaryContext\";\n\ntype UseErrorBoundaryState =\n | { error: Error; hasError: true }\n | { error: null; hasError: false };\n\nexport type UseErrorBoundaryApi = {\n error: Error | null;\n resetBoundary: () => void;\n showBoundary: (error: Error) => void;\n};\n\n/**\n * Convenience hook for imperatively showing or dismissing error boundaries.\n *\n * ⚠️ This hook must only be used within an `ErrorBoundary` subtree.\n */\nexport function useErrorBoundary(): {\n /**\n * The currently visible `Error` (if one has been thrown).\n */\n error: Error | null;\n\n /**\n * Method to reset and retry the nearest active error boundary (if one is active).\n */\n resetBoundary: () => void;\n\n /**\n * Trigger the nearest error boundary to display the error provided.\n *\n * ℹ️ React only handles errors thrown during render or during component lifecycle methods (e.g. effects and did-mount/did-update).\n * Errors thrown in event handlers, or after async code has run, will not be caught.\n * This method is a way to imperatively trigger an error boundary during these phases.\n */\n showBoundary: (error: Error) => void;\n} {\n const context = useContext(ErrorBoundaryContext);\n\n assertErrorBoundaryContext(context);\n\n const { error, resetErrorBoundary } = context;\n\n const [state, setState] = useState<UseErrorBoundaryState>({\n error: null,\n hasError: false,\n });\n\n const memoized = useMemo(\n () => ({\n error,\n resetBoundary: () => {\n resetErrorBoundary();\n setState({ error: null, hasError: false });\n },\n showBoundary: (error: Error) =>\n setState({\n error,\n hasError: true,\n }),\n }),\n [error, resetErrorBoundary],\n );\n\n if (state.hasError) {\n throw state.error;\n }\n\n return memoized;\n}\n","import {\n createElement,\n forwardRef,\n type ComponentClass,\n type ComponentType,\n} from \"react\";\nimport { ErrorBoundary } from \"../components/ErrorBoundary\";\nimport type { ErrorBoundaryProps } from \"../types\";\n\nexport function withErrorBoundary<\n Type extends ComponentClass<unknown>,\n Props extends object,\n>(Component: ComponentType<Props>, errorBoundaryProps: ErrorBoundaryProps) {\n const Wrapped = forwardRef<InstanceType<Type>, Props>((props, ref) =>\n createElement(\n ErrorBoundary,\n errorBoundaryProps,\n createElement(Component, { ...props, ref } as Props),\n ),\n );\n\n // Format for display in DevTools\n const name = Component.displayName || Component.name || \"Unknown\";\n Wrapped.displayName = `withErrorBoundary(${name})`;\n\n return Wrapped;\n}\n"],"names":["ErrorBoundaryContext","createContext","initialState","ErrorBoundary","Component","props","error","args","info","prevProps","prevState","didCatch","resetKeys","hasArrayChanged","children","fallbackRender","FallbackComponent","fallback","childToRender","createElement","a","b","item","index","isErrorBoundaryContext","value","assertErrorBoundaryContext","useErrorBoundary","context","useContext","resetErrorBoundary","state","setState","useState","memoized","useMemo","withErrorBoundary","errorBoundaryProps","Wrapped","forwardRef","ref","name"],"mappings":"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"}
|
|
@@ -1,2 +1,165 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { Component } from 'react';
|
|
2
|
+
import { ComponentClass } from 'react';
|
|
3
|
+
import { ComponentType } from 'react';
|
|
4
|
+
import { Context } from 'react';
|
|
5
|
+
import { ErrorInfo } from 'react';
|
|
6
|
+
import { ForwardRefExoticComponent } from 'react';
|
|
7
|
+
import { FunctionComponentElement } from 'react';
|
|
8
|
+
import { PropsWithChildren } from 'react';
|
|
9
|
+
import { PropsWithoutRef } from 'react';
|
|
10
|
+
import { ProviderProps } from 'react';
|
|
11
|
+
import { ReactNode } from 'react';
|
|
12
|
+
import { RefAttributes } from 'react';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component.
|
|
16
|
+
* Wrap this component around other React components to "catch" errors and render a fallback UI.
|
|
17
|
+
*
|
|
18
|
+
* This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),
|
|
19
|
+
* so it has all of the advantages and constraints of that API.
|
|
20
|
+
* This means that it can't catch errors during:
|
|
21
|
+
* - Server side rendering</li>
|
|
22
|
+
* - Event handlers
|
|
23
|
+
* - Asynchronous code (including effects)
|
|
24
|
+
*
|
|
25
|
+
* ℹ️ The component provides several ways to render a fallback: `fallback`, `fallbackRender`, and `FallbackComponent`.
|
|
26
|
+
* Refer to the documentation to determine which is best for your application.
|
|
27
|
+
*
|
|
28
|
+
* ℹ️ This is a **client component**. You can only pass props to it that are serializeable or use it in files that have a `"use client";` directive.
|
|
29
|
+
*/
|
|
30
|
+
export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
31
|
+
constructor(props: ErrorBoundaryProps);
|
|
32
|
+
static getDerivedStateFromError(error: Error): {
|
|
33
|
+
didCatch: boolean;
|
|
34
|
+
error: Error;
|
|
35
|
+
};
|
|
36
|
+
resetErrorBoundary(...args: unknown[]): void;
|
|
37
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
38
|
+
componentDidUpdate(prevProps: ErrorBoundaryProps, prevState: ErrorBoundaryState): void;
|
|
39
|
+
render(): FunctionComponentElement<ProviderProps<ErrorBoundaryContextType | null>>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export declare const ErrorBoundaryContext: Context<ErrorBoundaryContextType | null>;
|
|
43
|
+
|
|
44
|
+
export declare type ErrorBoundaryContextType = {
|
|
45
|
+
didCatch: boolean;
|
|
46
|
+
error: Error | null;
|
|
47
|
+
resetErrorBoundary: (...args: unknown[]) => void;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export declare type ErrorBoundaryProps = ErrorBoundaryPropsWithFallback | ErrorBoundaryPropsWithComponent | ErrorBoundaryPropsWithRender;
|
|
51
|
+
|
|
52
|
+
export declare type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
|
|
53
|
+
fallback?: never;
|
|
54
|
+
/**
|
|
55
|
+
* React component responsible for returning a fallback UI based on a thrown value.
|
|
56
|
+
*
|
|
57
|
+
* ```tsx
|
|
58
|
+
* <ErrorBoundary FallbackComponent={Fallback} />
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
FallbackComponent: ComponentType<FallbackProps>;
|
|
62
|
+
fallbackRender?: never;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export declare type ErrorBoundaryPropsWithFallback = ErrorBoundarySharedProps & {
|
|
66
|
+
/**
|
|
67
|
+
* Static content to render in place of an error if one is thrown.
|
|
68
|
+
*
|
|
69
|
+
* ```tsx
|
|
70
|
+
* <ErrorBoundary fallback={<div class="text-red">Something went wrong</div>} />
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
fallback: ReactNode;
|
|
74
|
+
FallbackComponent?: never;
|
|
75
|
+
fallbackRender?: never;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export declare type ErrorBoundaryPropsWithRender = ErrorBoundarySharedProps & {
|
|
79
|
+
fallback?: never;
|
|
80
|
+
FallbackComponent?: never;
|
|
81
|
+
/**
|
|
82
|
+
* [Render prop](https://react.dev/reference/react/Children#calling-a-render-prop-to-customize-rendering) function responsible for returning a fallback UI based on a thrown value.
|
|
83
|
+
*
|
|
84
|
+
* ```tsx
|
|
85
|
+
* <ErrorBoundary fallbackRender={({ error, resetErrorBoundary }) => <div>...</div>} />
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
fallbackRender: (props: FallbackProps) => ReactNode;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
declare type ErrorBoundarySharedProps = PropsWithChildren<{
|
|
92
|
+
/**
|
|
93
|
+
* Optional callback to enable e.g. logging error information to a server.
|
|
94
|
+
*
|
|
95
|
+
* @param error Error that was thrown
|
|
96
|
+
* @param info React "component stack" identifying where the error was thrown
|
|
97
|
+
*/
|
|
98
|
+
onError?: (error: Error, info: ErrorInfo) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Optional callback to to be notified when an error boundary is "reset" so React can retry the failed render.
|
|
101
|
+
*/
|
|
102
|
+
onReset?: (details: {
|
|
103
|
+
reason: "imperative-api";
|
|
104
|
+
args: unknown[];
|
|
105
|
+
} | {
|
|
106
|
+
reason: "keys";
|
|
107
|
+
prev: unknown[] | undefined;
|
|
108
|
+
next: unknown[] | undefined;
|
|
109
|
+
}) => void;
|
|
110
|
+
/**
|
|
111
|
+
* When changed, these keys will reset a triggered error boundary.
|
|
112
|
+
* This can be useful when an error condition may be tied to some specific state (that can be uniquely identified by key).
|
|
113
|
+
* See the the documentation for examples of how to use this prop.
|
|
114
|
+
*/
|
|
115
|
+
resetKeys?: unknown[];
|
|
116
|
+
}>;
|
|
117
|
+
|
|
118
|
+
declare type ErrorBoundaryState = {
|
|
119
|
+
didCatch: true;
|
|
120
|
+
error: Error;
|
|
121
|
+
} | {
|
|
122
|
+
didCatch: false;
|
|
123
|
+
error: null;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export declare type FallbackProps = {
|
|
127
|
+
error: Error;
|
|
128
|
+
resetErrorBoundary: (...args: unknown[]) => void;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export declare type OnErrorCallback = (error: Error, info: ErrorInfo) => void;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Convenience hook for imperatively showing or dismissing error boundaries.
|
|
135
|
+
*
|
|
136
|
+
* ⚠️ This hook must only be used within an `ErrorBoundary` subtree.
|
|
137
|
+
*/
|
|
138
|
+
export declare function useErrorBoundary(): {
|
|
139
|
+
/**
|
|
140
|
+
* The currently visible `Error` (if one has been thrown).
|
|
141
|
+
*/
|
|
142
|
+
error: Error | null;
|
|
143
|
+
/**
|
|
144
|
+
* Method to reset and retry the nearest active error boundary (if one is active).
|
|
145
|
+
*/
|
|
146
|
+
resetBoundary: () => void;
|
|
147
|
+
/**
|
|
148
|
+
* Trigger the nearest error boundary to display the error provided.
|
|
149
|
+
*
|
|
150
|
+
* ℹ️ React only handles errors thrown during render or during component lifecycle methods (e.g. effects and did-mount/did-update).
|
|
151
|
+
* Errors thrown in event handlers, or after async code has run, will not be caught.
|
|
152
|
+
* This method is a way to imperatively trigger an error boundary during these phases.
|
|
153
|
+
*/
|
|
154
|
+
showBoundary: (error: Error) => void;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export declare type UseErrorBoundaryApi = {
|
|
158
|
+
error: Error | null;
|
|
159
|
+
resetBoundary: () => void;
|
|
160
|
+
showBoundary: (error: Error) => void;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export declare function withErrorBoundary<Type extends ComponentClass<unknown>, Props extends object>(Component: ComponentType<Props>, errorBoundaryProps: ErrorBoundaryProps): ForwardRefExoticComponent<PropsWithoutRef<Props> & RefAttributes<InstanceType<Type>>>;
|
|
164
|
+
|
|
165
|
+
export { }
|
|
@@ -1,151 +1,111 @@
|
|
|
1
|
-
|
|
2
|
-
import { createContext, Component, createElement, useContext, useState, useMemo, forwardRef } from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const initialState = {
|
|
7
|
-
didCatch: false,
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext as l, Component as y, createElement as d, useContext as f, useState as p, useMemo as E, forwardRef as B } from "react";
|
|
3
|
+
const h = l(null), c = {
|
|
4
|
+
didCatch: !1,
|
|
8
5
|
error: null
|
|
9
6
|
};
|
|
10
|
-
class
|
|
11
|
-
constructor(
|
|
12
|
-
super(
|
|
13
|
-
this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
|
|
14
|
-
this.state = initialState;
|
|
7
|
+
class m extends y {
|
|
8
|
+
constructor(t) {
|
|
9
|
+
super(t), this.resetErrorBoundary = this.resetErrorBoundary.bind(this), this.state = c;
|
|
15
10
|
}
|
|
16
|
-
static getDerivedStateFromError(
|
|
17
|
-
return {
|
|
18
|
-
didCatch: true,
|
|
19
|
-
error
|
|
20
|
-
};
|
|
11
|
+
static getDerivedStateFromError(t) {
|
|
12
|
+
return { didCatch: !0, error: t };
|
|
21
13
|
}
|
|
22
|
-
resetErrorBoundary() {
|
|
23
|
-
const {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
29
|
-
args[_key] = arguments[_key];
|
|
30
|
-
}
|
|
31
|
-
(_this$props$onReset = (_this$props = this.props).onReset) === null || _this$props$onReset === void 0 ? void 0 : _this$props$onReset.call(_this$props, {
|
|
32
|
-
args,
|
|
33
|
-
reason: "imperative-api"
|
|
34
|
-
});
|
|
35
|
-
this.setState(initialState);
|
|
36
|
-
}
|
|
14
|
+
resetErrorBoundary(...t) {
|
|
15
|
+
const { error: e } = this.state;
|
|
16
|
+
e !== null && (this.props.onReset?.({
|
|
17
|
+
args: t,
|
|
18
|
+
reason: "imperative-api"
|
|
19
|
+
}), this.setState(c));
|
|
37
20
|
}
|
|
38
|
-
componentDidCatch(
|
|
39
|
-
|
|
40
|
-
(_this$props$onError = (_this$props2 = this.props).onError) === null || _this$props$onError === void 0 ? void 0 : _this$props$onError.call(_this$props2, error, info);
|
|
21
|
+
componentDidCatch(t, e) {
|
|
22
|
+
this.props.onError?.(t, e);
|
|
41
23
|
}
|
|
42
|
-
componentDidUpdate(
|
|
43
|
-
const {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// There's an edge case where if the thing that triggered the error happens to *also* be in the resetKeys array,
|
|
51
|
-
// we'd end up resetting the error boundary immediately.
|
|
52
|
-
// This would likely trigger a second error to be thrown.
|
|
53
|
-
// So we make sure that we don't check the resetKeys on the first call of cDU after the error is set.
|
|
54
|
-
|
|
55
|
-
if (didCatch && prevState.error !== null && hasArrayChanged(prevProps.resetKeys, resetKeys)) {
|
|
56
|
-
var _this$props$onReset2, _this$props3;
|
|
57
|
-
(_this$props$onReset2 = (_this$props3 = this.props).onReset) === null || _this$props$onReset2 === void 0 ? void 0 : _this$props$onReset2.call(_this$props3, {
|
|
58
|
-
next: resetKeys,
|
|
59
|
-
prev: prevProps.resetKeys,
|
|
60
|
-
reason: "keys"
|
|
61
|
-
});
|
|
62
|
-
this.setState(initialState);
|
|
63
|
-
}
|
|
24
|
+
componentDidUpdate(t, e) {
|
|
25
|
+
const { didCatch: o } = this.state, { resetKeys: n } = this.props;
|
|
26
|
+
o && e.error !== null && C(t.resetKeys, n) && (this.props.onReset?.({
|
|
27
|
+
next: n,
|
|
28
|
+
prev: t.resetKeys,
|
|
29
|
+
reason: "keys"
|
|
30
|
+
}), this.setState(c));
|
|
64
31
|
}
|
|
65
32
|
render() {
|
|
66
|
-
const {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
} = this.props;
|
|
72
|
-
const {
|
|
73
|
-
didCatch,
|
|
74
|
-
error
|
|
75
|
-
} = this.state;
|
|
76
|
-
let childToRender = children;
|
|
77
|
-
if (didCatch) {
|
|
78
|
-
const props = {
|
|
79
|
-
error,
|
|
33
|
+
const { children: t, fallbackRender: e, FallbackComponent: o, fallback: n } = this.props, { didCatch: s, error: a } = this.state;
|
|
34
|
+
let i = t;
|
|
35
|
+
if (s) {
|
|
36
|
+
const u = {
|
|
37
|
+
error: a,
|
|
80
38
|
resetErrorBoundary: this.resetErrorBoundary
|
|
81
39
|
};
|
|
82
|
-
if (typeof
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
throw
|
|
90
|
-
}
|
|
40
|
+
if (typeof e == "function")
|
|
41
|
+
i = e(u);
|
|
42
|
+
else if (o)
|
|
43
|
+
i = d(o, u);
|
|
44
|
+
else if (n !== void 0)
|
|
45
|
+
i = n;
|
|
46
|
+
else
|
|
47
|
+
throw a;
|
|
91
48
|
}
|
|
92
|
-
return
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
49
|
+
return d(
|
|
50
|
+
h.Provider,
|
|
51
|
+
{
|
|
52
|
+
value: {
|
|
53
|
+
didCatch: s,
|
|
54
|
+
error: a,
|
|
55
|
+
resetErrorBoundary: this.resetErrorBoundary
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
i
|
|
59
|
+
);
|
|
99
60
|
}
|
|
100
61
|
}
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
62
|
+
function C(r = [], t = []) {
|
|
63
|
+
return r.length !== t.length || r.some((e, o) => !Object.is(e, t[o]));
|
|
64
|
+
}
|
|
65
|
+
function x(r) {
|
|
66
|
+
return r !== null && typeof r == "object" && "didCatch" in r && typeof r.didCatch == "boolean" && "error" in r && "resetErrorBoundary" in r && typeof r.resetErrorBoundary == "function";
|
|
105
67
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (value == null || typeof value.didCatch !== "boolean" || typeof value.resetErrorBoundary !== "function") {
|
|
68
|
+
function w(r) {
|
|
69
|
+
if (!x(r))
|
|
109
70
|
throw new Error("ErrorBoundaryContext not found");
|
|
110
|
-
}
|
|
111
71
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const [state, setState] = useState({
|
|
72
|
+
function S() {
|
|
73
|
+
const r = f(h);
|
|
74
|
+
w(r);
|
|
75
|
+
const { error: t, resetErrorBoundary: e } = r, [o, n] = p({
|
|
117
76
|
error: null,
|
|
118
|
-
hasError:
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
return memoized;
|
|
77
|
+
hasError: !1
|
|
78
|
+
}), s = E(
|
|
79
|
+
() => ({
|
|
80
|
+
error: t,
|
|
81
|
+
resetBoundary: () => {
|
|
82
|
+
e(), n({ error: null, hasError: !1 });
|
|
83
|
+
},
|
|
84
|
+
showBoundary: (a) => n({
|
|
85
|
+
error: a,
|
|
86
|
+
hasError: !0
|
|
87
|
+
})
|
|
88
|
+
}),
|
|
89
|
+
[t, e]
|
|
90
|
+
);
|
|
91
|
+
if (o.hasError)
|
|
92
|
+
throw o.error;
|
|
93
|
+
return s;
|
|
137
94
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Wrapped.displayName = "withErrorBoundary(".concat(name, ")");
|
|
148
|
-
return Wrapped;
|
|
95
|
+
function k(r, t) {
|
|
96
|
+
const e = B(
|
|
97
|
+
(n, s) => d(
|
|
98
|
+
m,
|
|
99
|
+
t,
|
|
100
|
+
d(r, { ...n, ref: s })
|
|
101
|
+
)
|
|
102
|
+
), o = r.displayName || r.name || "Unknown";
|
|
103
|
+
return e.displayName = `withErrorBoundary(${o})`, e;
|
|
149
104
|
}
|
|
150
|
-
|
|
151
|
-
|
|
105
|
+
export {
|
|
106
|
+
m as ErrorBoundary,
|
|
107
|
+
h as ErrorBoundaryContext,
|
|
108
|
+
S as useErrorBoundary,
|
|
109
|
+
k as withErrorBoundary
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=react-error-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-error-boundary.js","sources":["../lib/context/ErrorBoundaryContext.ts","../lib/components/ErrorBoundary.tsx","../lib/utils/isErrorBoundaryContext.ts","../lib/utils/assertErrorBoundaryContext.ts","../lib/hooks/useErrorBoundary.ts","../lib/utils/withErrorBoundary.ts"],"sourcesContent":["import { createContext } from \"react\";\n\nexport type ErrorBoundaryContextType = {\n didCatch: boolean;\n error: Error | null;\n resetErrorBoundary: (...args: unknown[]) => void;\n};\n\nexport const ErrorBoundaryContext =\n createContext<ErrorBoundaryContextType | null>(null);\n","import { Component, createElement, type ErrorInfo } from \"react\";\nimport { ErrorBoundaryContext } from \"../context/ErrorBoundaryContext\";\nimport type { ErrorBoundaryProps, FallbackProps } from \"../types\";\n\nconst isDevelopment = import.meta.env.DEV;\n\ntype ErrorBoundaryState =\n | {\n didCatch: true;\n error: Error;\n }\n | {\n didCatch: false;\n error: null;\n };\n\nconst initialState: ErrorBoundaryState = {\n didCatch: false,\n error: null,\n};\n\n/**\n * A reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component.\n * Wrap this component around other React components to \"catch\" errors and render a fallback UI.\n *\n * This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),\n * so it has all of the advantages and constraints of that API.\n * This means that it can't catch errors during:\n * - Server side rendering</li>\n * - Event handlers\n * - Asynchronous code (including effects)\n *\n * ℹ️ The component provides several ways to render a fallback: `fallback`, `fallbackRender`, and `FallbackComponent`.\n * Refer to the documentation to determine which is best for your application.\n *\n * ℹ️ This is a **client component**. You can only pass props to it that are serializeable or use it in files that have a `\"use client\";` directive.\n */\nexport class ErrorBoundary extends Component<\n ErrorBoundaryProps,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n\n this.resetErrorBoundary = this.resetErrorBoundary.bind(this);\n this.state = initialState;\n }\n\n static getDerivedStateFromError(error: Error) {\n return { didCatch: true, error };\n }\n\n resetErrorBoundary(...args: unknown[]) {\n const { error } = this.state;\n\n if (error !== null) {\n this.props.onReset?.({\n args,\n reason: \"imperative-api\",\n });\n\n this.setState(initialState);\n }\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n this.props.onError?.(error, info);\n }\n\n componentDidUpdate(\n prevProps: ErrorBoundaryProps,\n prevState: ErrorBoundaryState,\n ) {\n const { didCatch } = this.state;\n const { resetKeys } = this.props;\n\n // There's an edge case where if the thing that triggered the error happens to *also* be in the resetKeys array,\n // we'd end up resetting the error boundary immediately.\n // This would likely trigger a second error to be thrown.\n // So we make sure that we don't check the resetKeys on the first call of cDU after the error is set.\n\n if (\n didCatch &&\n prevState.error !== null &&\n hasArrayChanged(prevProps.resetKeys, resetKeys)\n ) {\n this.props.onReset?.({\n next: resetKeys,\n prev: prevProps.resetKeys,\n reason: \"keys\",\n });\n\n this.setState(initialState);\n }\n }\n\n render() {\n const { children, fallbackRender, FallbackComponent, fallback } =\n this.props;\n const { didCatch, error } = this.state;\n\n let childToRender = children;\n\n if (didCatch) {\n const props: FallbackProps = {\n error,\n resetErrorBoundary: this.resetErrorBoundary,\n };\n\n if (typeof fallbackRender === \"function\") {\n childToRender = fallbackRender(props);\n } else if (FallbackComponent) {\n childToRender = createElement(FallbackComponent, props);\n } else if (fallback !== undefined) {\n childToRender = fallback;\n } else {\n if (isDevelopment) {\n console.error(\n \"react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop\",\n );\n }\n\n throw error;\n }\n }\n\n return createElement(\n ErrorBoundaryContext.Provider,\n {\n value: {\n didCatch,\n error,\n resetErrorBoundary: this.resetErrorBoundary,\n },\n },\n childToRender,\n );\n }\n}\n\nfunction hasArrayChanged(a: unknown[] = [], b: unknown[] = []) {\n return (\n a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]))\n );\n}\n","import type { ErrorBoundaryContextType } from \"../context/ErrorBoundaryContext\";\n\nexport function isErrorBoundaryContext(\n value: unknown,\n): value is ErrorBoundaryContextType {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"didCatch\" in value &&\n typeof value.didCatch === \"boolean\" &&\n \"error\" in value &&\n \"resetErrorBoundary\" in value &&\n typeof value.resetErrorBoundary === \"function\"\n );\n}\n","import type { ErrorBoundaryContextType } from \"../context/ErrorBoundaryContext\";\nimport { isErrorBoundaryContext } from \"./isErrorBoundaryContext\";\n\nexport function assertErrorBoundaryContext(\n value: unknown,\n): asserts value is ErrorBoundaryContextType {\n if (!isErrorBoundaryContext(value)) {\n throw new Error(\"ErrorBoundaryContext not found\");\n }\n}\n","import { useContext, useMemo, useState } from \"react\";\nimport { ErrorBoundaryContext } from \"../context/ErrorBoundaryContext\";\nimport { assertErrorBoundaryContext } from \"../utils/assertErrorBoundaryContext\";\n\ntype UseErrorBoundaryState =\n | { error: Error; hasError: true }\n | { error: null; hasError: false };\n\nexport type UseErrorBoundaryApi = {\n error: Error | null;\n resetBoundary: () => void;\n showBoundary: (error: Error) => void;\n};\n\n/**\n * Convenience hook for imperatively showing or dismissing error boundaries.\n *\n * ⚠️ This hook must only be used within an `ErrorBoundary` subtree.\n */\nexport function useErrorBoundary(): {\n /**\n * The currently visible `Error` (if one has been thrown).\n */\n error: Error | null;\n\n /**\n * Method to reset and retry the nearest active error boundary (if one is active).\n */\n resetBoundary: () => void;\n\n /**\n * Trigger the nearest error boundary to display the error provided.\n *\n * ℹ️ React only handles errors thrown during render or during component lifecycle methods (e.g. effects and did-mount/did-update).\n * Errors thrown in event handlers, or after async code has run, will not be caught.\n * This method is a way to imperatively trigger an error boundary during these phases.\n */\n showBoundary: (error: Error) => void;\n} {\n const context = useContext(ErrorBoundaryContext);\n\n assertErrorBoundaryContext(context);\n\n const { error, resetErrorBoundary } = context;\n\n const [state, setState] = useState<UseErrorBoundaryState>({\n error: null,\n hasError: false,\n });\n\n const memoized = useMemo(\n () => ({\n error,\n resetBoundary: () => {\n resetErrorBoundary();\n setState({ error: null, hasError: false });\n },\n showBoundary: (error: Error) =>\n setState({\n error,\n hasError: true,\n }),\n }),\n [error, resetErrorBoundary],\n );\n\n if (state.hasError) {\n throw state.error;\n }\n\n return memoized;\n}\n","import {\n createElement,\n forwardRef,\n type ComponentClass,\n type ComponentType,\n} from \"react\";\nimport { ErrorBoundary } from \"../components/ErrorBoundary\";\nimport type { ErrorBoundaryProps } from \"../types\";\n\nexport function withErrorBoundary<\n Type extends ComponentClass<unknown>,\n Props extends object,\n>(Component: ComponentType<Props>, errorBoundaryProps: ErrorBoundaryProps) {\n const Wrapped = forwardRef<InstanceType<Type>, Props>((props, ref) =>\n createElement(\n ErrorBoundary,\n errorBoundaryProps,\n createElement(Component, { ...props, ref } as Props),\n ),\n );\n\n // Format for display in DevTools\n const name = Component.displayName || Component.name || \"Unknown\";\n Wrapped.displayName = `withErrorBoundary(${name})`;\n\n return Wrapped;\n}\n"],"names":["ErrorBoundaryContext","createContext","initialState","ErrorBoundary","Component","props","error","args","info","prevProps","prevState","didCatch","resetKeys","hasArrayChanged","children","fallbackRender","FallbackComponent","fallback","childToRender","createElement","a","b","item","index","isErrorBoundaryContext","value","assertErrorBoundaryContext","useErrorBoundary","context","useContext","resetErrorBoundary","state","setState","useState","memoized","useMemo","withErrorBoundary","errorBoundaryProps","Wrapped","forwardRef","ref","name"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-error-boundary",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Simple reusable React error boundary component",
|
|
6
6
|
"author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
|
|
@@ -9,73 +9,117 @@
|
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "https://github.com/bvaughn/react-error-boundary"
|
|
11
11
|
},
|
|
12
|
-
"
|
|
13
|
-
"."
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
"contributors": [
|
|
13
|
+
"Brian Vaughn <brian.david.vaughn@gmail.com> (https://github.com/bvaughn/)"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://react-error-boundary-lib.vercel.app/",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react",
|
|
18
|
+
"reactjs",
|
|
19
|
+
"virtual",
|
|
20
|
+
"window",
|
|
21
|
+
"windowed",
|
|
22
|
+
"list",
|
|
23
|
+
"scrolling",
|
|
24
|
+
"infinite",
|
|
25
|
+
"virtualized",
|
|
26
|
+
"table",
|
|
27
|
+
"grid",
|
|
28
|
+
"spreadsheet"
|
|
29
|
+
],
|
|
30
|
+
"main": "dist/react-error-boundary.cjs",
|
|
31
|
+
"module": "dist/react-error-boundary.js",
|
|
26
32
|
"types": "dist/react-error-boundary.d.ts",
|
|
27
33
|
"files": [
|
|
28
34
|
"dist"
|
|
29
35
|
],
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
"
|
|
36
|
+
"scripts": {
|
|
37
|
+
"dev": "vite",
|
|
38
|
+
"dev:integrations": "pnpm -C integrations/vite/ run dev",
|
|
39
|
+
"build": "pnpm run build:lib && pnpm run build:docs",
|
|
40
|
+
"build:docs": "TARGET=docs vite build",
|
|
41
|
+
"build:lib": "TARGET=lib vite build",
|
|
42
|
+
"compile": "pnpm run compile:docs && pnpm run compile:examples",
|
|
43
|
+
"compile:docs": "tsx ./scripts/compile-docs",
|
|
44
|
+
"compile:examples": "tsx ./scripts/compile-examples",
|
|
45
|
+
"compress:og-image": "tsx ./scripts/compress-og-image",
|
|
46
|
+
"lint": "eslint .",
|
|
47
|
+
"prerelease": "rm -rf dist && pnpm run build:lib",
|
|
48
|
+
"prettier": "prettier --write \"**/*.{css,html,js,json,jsx,ts,tsx}\"",
|
|
49
|
+
"prettier:ci": "prettier --check \"**/*.{css,html,js,json,jsx,ts,tsx}\"",
|
|
50
|
+
"preview": "vite preview",
|
|
51
|
+
"test": "vitest",
|
|
52
|
+
"test:ci": "vitest run",
|
|
53
|
+
"test:debug": "vitest --inspect-brk=127.0.0.1:3000 --no-file-parallelism",
|
|
54
|
+
"tsc": "tsc -b"
|
|
33
55
|
},
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"@babel/preset-typescript": "^7.21.5",
|
|
37
|
-
"@preconstruct/cli": "^2.8.12",
|
|
38
|
-
"@types/assert": "^1.5.10",
|
|
39
|
-
"@types/react": "^18.3.17",
|
|
40
|
-
"@types/react-dom": "^18",
|
|
41
|
-
"assert": "^2.0.0",
|
|
42
|
-
"eslint": "^9.13.0",
|
|
43
|
-
"eslint-config-prettier": "^9.1.0",
|
|
44
|
-
"eslint-plugin-import": "^2.25.2",
|
|
45
|
-
"eslint-plugin-prettier": "^5.2.1",
|
|
46
|
-
"eslint-plugin-react": "^7.37.2",
|
|
47
|
-
"globals": "^15.11.0",
|
|
48
|
-
"prettier": "^3.0.1",
|
|
49
|
-
"react": "^18",
|
|
50
|
-
"react-dom": "^18",
|
|
51
|
-
"rimraf": "^6.0.1",
|
|
52
|
-
"vitest": "^3.1.2",
|
|
53
|
-
"typescript": "^5.8.3",
|
|
54
|
-
"typescript-eslint": "^8.18.0"
|
|
56
|
+
"lint-staged": {
|
|
57
|
+
"**/*": "prettier --write --ignore-unknown"
|
|
55
58
|
},
|
|
56
59
|
"peerDependencies": {
|
|
57
|
-
"react": "
|
|
58
|
-
|
|
59
|
-
"preconstruct": {
|
|
60
|
-
"exports": {
|
|
61
|
-
"importConditionDefaultExport": "default"
|
|
62
|
-
},
|
|
63
|
-
"___experimentalFlags_WILL_CHANGE_IN_PATCH": {
|
|
64
|
-
"distInRoot": true,
|
|
65
|
-
"importsConditions": true,
|
|
66
|
-
"typeModule": true
|
|
67
|
-
}
|
|
60
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
61
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
68
62
|
},
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@csstools/postcss-oklab-function": "^4.0.11",
|
|
65
|
+
"@eslint/js": "^9.30.1",
|
|
66
|
+
"@headlessui/react": "^2.2.4",
|
|
67
|
+
"@headlessui/tailwindcss": "^0.2.2",
|
|
68
|
+
"@heroicons/react": "^2.2.0",
|
|
69
|
+
"@tailwindcss/vite": "^4.1.11",
|
|
70
|
+
"@tailwindplus/elements": "^1.0.5",
|
|
71
|
+
"@testing-library/jest-dom": "^6.6.4",
|
|
72
|
+
"@testing-library/react": "^16.3.0",
|
|
73
|
+
"@testing-library/user-event": "^14.6.1",
|
|
74
|
+
"@types/bytes": "^3.1.5",
|
|
75
|
+
"@types/compression": "^1.8.1",
|
|
76
|
+
"@types/markdown-it": "^14.1.2",
|
|
77
|
+
"@types/node": "^24.2.0",
|
|
78
|
+
"@types/react": "^19.1.8",
|
|
79
|
+
"@types/react-dom": "^19.2.3",
|
|
80
|
+
"@types/sharp": "^0.32.0",
|
|
81
|
+
"@vitejs/plugin-react-swc": "^3.10.2",
|
|
82
|
+
"bytes": "^3.1.2",
|
|
83
|
+
"clsx": "^2.1.1",
|
|
84
|
+
"compression": "^1.8.1",
|
|
85
|
+
"csstype": "^3.1.3",
|
|
86
|
+
"eslint": "^9.30.1",
|
|
87
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
88
|
+
"eslint-plugin-react-refresh": "^0.4.20",
|
|
89
|
+
"globals": "^16.3.0",
|
|
90
|
+
"husky": "^9.1.7",
|
|
91
|
+
"jsdom": "^26.1.0",
|
|
92
|
+
"lint-staged": "^16.1.4",
|
|
93
|
+
"markdown-it": "^14.1.0",
|
|
94
|
+
"marked": "^16.4.1",
|
|
95
|
+
"postcss": "^8.5.6",
|
|
96
|
+
"prettier": "3.6.2",
|
|
97
|
+
"prettier-plugin-tailwindcss": "^0.7.1",
|
|
98
|
+
"react": "^19.2.3",
|
|
99
|
+
"react-docgen-typescript": "^2.4.0",
|
|
100
|
+
"react-dom": "^19.2.3",
|
|
101
|
+
"react-error-boundary": "^6.0.0",
|
|
102
|
+
"react-lib-tools": "^0.0.30",
|
|
103
|
+
"react-router-dom": "^7.6.3",
|
|
104
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
105
|
+
"rollup-plugin-visualizer": "^6.0.3",
|
|
106
|
+
"rollup-preserve-directives": "^1.1.3",
|
|
107
|
+
"sharp": "^0.34.5",
|
|
108
|
+
"sirv": "^3.0.2",
|
|
109
|
+
"tailwind-merge": "^3.3.1",
|
|
110
|
+
"tailwindcss": "^4.1.11",
|
|
111
|
+
"terser": "^5.43.1",
|
|
112
|
+
"ts-blank-space": "^0.6.2",
|
|
113
|
+
"ts-node": "^10.9.2",
|
|
114
|
+
"tsx": "^4.21.0",
|
|
115
|
+
"typescript": "~5.8.3",
|
|
116
|
+
"typescript-eslint": "^8.35.1",
|
|
117
|
+
"typescript-json-schema": "^0.65.1",
|
|
118
|
+
"vite": "^7.0.4",
|
|
119
|
+
"vite-plugin-dts": "^4.5.4",
|
|
120
|
+
"vite-plugin-svgr": "^4.3.0",
|
|
121
|
+
"vitest": "^3.2.4",
|
|
122
|
+
"vitest-fail-on-console": "^0.10.1",
|
|
123
|
+
"zustand": "^5.0.7"
|
|
80
124
|
}
|
|
81
|
-
}
|
|
125
|
+
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Component, ErrorInfo } from "react";
|
|
2
|
-
import { ErrorBoundaryProps } from "./types.js";
|
|
3
|
-
type ErrorBoundaryState = {
|
|
4
|
-
didCatch: true;
|
|
5
|
-
error: any;
|
|
6
|
-
} | {
|
|
7
|
-
didCatch: false;
|
|
8
|
-
error: null;
|
|
9
|
-
};
|
|
10
|
-
export declare class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
11
|
-
constructor(props: ErrorBoundaryProps);
|
|
12
|
-
static getDerivedStateFromError(error: Error): {
|
|
13
|
-
didCatch: boolean;
|
|
14
|
-
error: Error;
|
|
15
|
-
};
|
|
16
|
-
resetErrorBoundary(...args: any[]): void;
|
|
17
|
-
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
18
|
-
componentDidUpdate(prevProps: ErrorBoundaryProps, prevState: ErrorBoundaryState): void;
|
|
19
|
-
render(): import("react").FunctionComponentElement<import("react").ProviderProps<import("./ErrorBoundaryContext.js").ErrorBoundaryContextType | null>>;
|
|
20
|
-
}
|
|
21
|
-
export {};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { ComponentType, ErrorInfo, PropsWithChildren, ReactNode } from "react";
|
|
2
|
-
export type FallbackProps = {
|
|
3
|
-
error: any;
|
|
4
|
-
resetErrorBoundary: (...args: any[]) => void;
|
|
5
|
-
};
|
|
6
|
-
type ErrorBoundarySharedProps = PropsWithChildren<{
|
|
7
|
-
onError?: (error: Error, info: ErrorInfo) => void;
|
|
8
|
-
onReset?: (details: {
|
|
9
|
-
reason: "imperative-api";
|
|
10
|
-
args: any[];
|
|
11
|
-
} | {
|
|
12
|
-
reason: "keys";
|
|
13
|
-
prev: any[] | undefined;
|
|
14
|
-
next: any[] | undefined;
|
|
15
|
-
}) => void;
|
|
16
|
-
resetKeys?: any[];
|
|
17
|
-
}>;
|
|
18
|
-
export type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
|
|
19
|
-
fallback?: never;
|
|
20
|
-
FallbackComponent: ComponentType<FallbackProps>;
|
|
21
|
-
fallbackRender?: never;
|
|
22
|
-
};
|
|
23
|
-
export type ErrorBoundaryPropsWithRender = ErrorBoundarySharedProps & {
|
|
24
|
-
fallback?: never;
|
|
25
|
-
FallbackComponent?: never;
|
|
26
|
-
fallbackRender: (props: FallbackProps) => ReactNode;
|
|
27
|
-
};
|
|
28
|
-
export type ErrorBoundaryPropsWithFallback = ErrorBoundarySharedProps & {
|
|
29
|
-
fallback: ReactNode;
|
|
30
|
-
FallbackComponent?: never;
|
|
31
|
-
fallbackRender?: never;
|
|
32
|
-
};
|
|
33
|
-
export type ErrorBoundaryProps = ErrorBoundaryPropsWithFallback | ErrorBoundaryPropsWithComponent | ErrorBoundaryPropsWithRender;
|
|
34
|
-
export {};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { RefAttributes, ForwardRefExoticComponent, PropsWithoutRef, ComponentType, ComponentRef, ComponentProps } from "react";
|
|
2
|
-
import { ErrorBoundaryProps } from "./types.js";
|
|
3
|
-
export declare function withErrorBoundary<T extends ComponentType<any>>(component: T, errorBoundaryProps: ErrorBoundaryProps): ForwardRefExoticComponent<PropsWithoutRef<ComponentProps<T>> & RefAttributes<ComponentRef<T>>>;
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { createContext, Component, createElement, useContext, useState, useMemo, forwardRef } from 'react';
|
|
3
|
-
|
|
4
|
-
const ErrorBoundaryContext = createContext(null);
|
|
5
|
-
|
|
6
|
-
const initialState = {
|
|
7
|
-
didCatch: false,
|
|
8
|
-
error: null
|
|
9
|
-
};
|
|
10
|
-
class ErrorBoundary extends Component {
|
|
11
|
-
constructor(props) {
|
|
12
|
-
super(props);
|
|
13
|
-
this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
|
|
14
|
-
this.state = initialState;
|
|
15
|
-
}
|
|
16
|
-
static getDerivedStateFromError(error) {
|
|
17
|
-
return {
|
|
18
|
-
didCatch: true,
|
|
19
|
-
error
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
resetErrorBoundary() {
|
|
23
|
-
const {
|
|
24
|
-
error
|
|
25
|
-
} = this.state;
|
|
26
|
-
if (error !== null) {
|
|
27
|
-
var _this$props$onReset, _this$props;
|
|
28
|
-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
29
|
-
args[_key] = arguments[_key];
|
|
30
|
-
}
|
|
31
|
-
(_this$props$onReset = (_this$props = this.props).onReset) === null || _this$props$onReset === void 0 ? void 0 : _this$props$onReset.call(_this$props, {
|
|
32
|
-
args,
|
|
33
|
-
reason: "imperative-api"
|
|
34
|
-
});
|
|
35
|
-
this.setState(initialState);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
componentDidCatch(error, info) {
|
|
39
|
-
var _this$props$onError, _this$props2;
|
|
40
|
-
(_this$props$onError = (_this$props2 = this.props).onError) === null || _this$props$onError === void 0 ? void 0 : _this$props$onError.call(_this$props2, error, info);
|
|
41
|
-
}
|
|
42
|
-
componentDidUpdate(prevProps, prevState) {
|
|
43
|
-
const {
|
|
44
|
-
didCatch
|
|
45
|
-
} = this.state;
|
|
46
|
-
const {
|
|
47
|
-
resetKeys
|
|
48
|
-
} = this.props;
|
|
49
|
-
|
|
50
|
-
// There's an edge case where if the thing that triggered the error happens to *also* be in the resetKeys array,
|
|
51
|
-
// we'd end up resetting the error boundary immediately.
|
|
52
|
-
// This would likely trigger a second error to be thrown.
|
|
53
|
-
// So we make sure that we don't check the resetKeys on the first call of cDU after the error is set.
|
|
54
|
-
|
|
55
|
-
if (didCatch && prevState.error !== null && hasArrayChanged(prevProps.resetKeys, resetKeys)) {
|
|
56
|
-
var _this$props$onReset2, _this$props3;
|
|
57
|
-
(_this$props$onReset2 = (_this$props3 = this.props).onReset) === null || _this$props$onReset2 === void 0 ? void 0 : _this$props$onReset2.call(_this$props3, {
|
|
58
|
-
next: resetKeys,
|
|
59
|
-
prev: prevProps.resetKeys,
|
|
60
|
-
reason: "keys"
|
|
61
|
-
});
|
|
62
|
-
this.setState(initialState);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
render() {
|
|
66
|
-
const {
|
|
67
|
-
children,
|
|
68
|
-
fallbackRender,
|
|
69
|
-
FallbackComponent,
|
|
70
|
-
fallback
|
|
71
|
-
} = this.props;
|
|
72
|
-
const {
|
|
73
|
-
didCatch,
|
|
74
|
-
error
|
|
75
|
-
} = this.state;
|
|
76
|
-
let childToRender = children;
|
|
77
|
-
if (didCatch) {
|
|
78
|
-
const props = {
|
|
79
|
-
error,
|
|
80
|
-
resetErrorBoundary: this.resetErrorBoundary
|
|
81
|
-
};
|
|
82
|
-
if (typeof fallbackRender === "function") {
|
|
83
|
-
childToRender = fallbackRender(props);
|
|
84
|
-
} else if (FallbackComponent) {
|
|
85
|
-
childToRender = createElement(FallbackComponent, props);
|
|
86
|
-
} else if (fallback !== undefined) {
|
|
87
|
-
childToRender = fallback;
|
|
88
|
-
} else {
|
|
89
|
-
{
|
|
90
|
-
console.error("react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop");
|
|
91
|
-
}
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return createElement(ErrorBoundaryContext.Provider, {
|
|
96
|
-
value: {
|
|
97
|
-
didCatch,
|
|
98
|
-
error,
|
|
99
|
-
resetErrorBoundary: this.resetErrorBoundary
|
|
100
|
-
}
|
|
101
|
-
}, childToRender);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
function hasArrayChanged() {
|
|
105
|
-
let a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
106
|
-
let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
107
|
-
return a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function assertErrorBoundaryContext(value) {
|
|
111
|
-
if (value == null || typeof value.didCatch !== "boolean" || typeof value.resetErrorBoundary !== "function") {
|
|
112
|
-
throw new Error("ErrorBoundaryContext not found");
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function useErrorBoundary() {
|
|
117
|
-
const context = useContext(ErrorBoundaryContext);
|
|
118
|
-
assertErrorBoundaryContext(context);
|
|
119
|
-
const [state, setState] = useState({
|
|
120
|
-
error: null,
|
|
121
|
-
hasError: false
|
|
122
|
-
});
|
|
123
|
-
const memoized = useMemo(() => ({
|
|
124
|
-
resetBoundary: () => {
|
|
125
|
-
context.resetErrorBoundary();
|
|
126
|
-
setState({
|
|
127
|
-
error: null,
|
|
128
|
-
hasError: false
|
|
129
|
-
});
|
|
130
|
-
},
|
|
131
|
-
showBoundary: error => setState({
|
|
132
|
-
error,
|
|
133
|
-
hasError: true
|
|
134
|
-
})
|
|
135
|
-
}), [context.resetErrorBoundary]);
|
|
136
|
-
if (state.hasError) {
|
|
137
|
-
throw state.error;
|
|
138
|
-
}
|
|
139
|
-
return memoized;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function withErrorBoundary(component, errorBoundaryProps) {
|
|
143
|
-
const Wrapped = forwardRef((props, ref) => createElement(ErrorBoundary, errorBoundaryProps, createElement(component, {
|
|
144
|
-
...props,
|
|
145
|
-
ref
|
|
146
|
-
})));
|
|
147
|
-
|
|
148
|
-
// Format for display in DevTools
|
|
149
|
-
const name = component.displayName || component.name || "Unknown";
|
|
150
|
-
Wrapped.displayName = "withErrorBoundary(".concat(name, ")");
|
|
151
|
-
return Wrapped;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export { ErrorBoundary, ErrorBoundaryContext, useErrorBoundary, withErrorBoundary };
|