UNPKG

4.85 kBJavaScriptView Raw
1'use client';
2'use strict';
3
4Object.defineProperty(exports, '__esModule', { value: true });
5
6var react = require('react');
7
8const ErrorBoundaryContext = react.createContext(null);
9
10const initialState = {
11 didCatch: false,
12 error: null
13};
14class ErrorBoundary extends react.Component {
15 constructor(props) {
16 super(props);
17 this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
18 this.state = initialState;
19 }
20 static getDerivedStateFromError(error) {
21 return {
22 didCatch: true,
23 error
24 };
25 }
26 resetErrorBoundary() {
27 const {
28 error
29 } = this.state;
30 if (error !== null) {
31 var _this$props$onReset, _this$props;
32 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
33 args[_key] = arguments[_key];
34 }
35 (_this$props$onReset = (_this$props = this.props).onReset) === null || _this$props$onReset === void 0 ? void 0 : _this$props$onReset.call(_this$props, {
36 args,
37 reason: "imperative-api"
38 });
39 this.setState(initialState);
40 }
41 }
42 componentDidCatch(error, info) {
43 var _this$props$onError, _this$props2;
44 (_this$props$onError = (_this$props2 = this.props).onError) === null || _this$props$onError === void 0 ? void 0 : _this$props$onError.call(_this$props2, error, info);
45 }
46 componentDidUpdate(prevProps, prevState) {
47 const {
48 didCatch
49 } = this.state;
50 const {
51 resetKeys
52 } = this.props;
53
54 // There's an edge case where if the thing that triggered the error happens to *also* be in the resetKeys array,
55 // we'd end up resetting the error boundary immediately.
56 // This would likely trigger a second error to be thrown.
57 // So we make sure that we don't check the resetKeys on the first call of cDU after the error is set.
58
59 if (didCatch && prevState.error !== null && hasArrayChanged(prevProps.resetKeys, resetKeys)) {
60 var _this$props$onReset2, _this$props3;
61 (_this$props$onReset2 = (_this$props3 = this.props).onReset) === null || _this$props$onReset2 === void 0 ? void 0 : _this$props$onReset2.call(_this$props3, {
62 next: resetKeys,
63 prev: prevProps.resetKeys,
64 reason: "keys"
65 });
66 this.setState(initialState);
67 }
68 }
69 render() {
70 const {
71 children,
72 fallbackRender,
73 FallbackComponent,
74 fallback
75 } = this.props;
76 const {
77 didCatch,
78 error
79 } = this.state;
80 let childToRender = children;
81 if (didCatch) {
82 const props = {
83 error,
84 resetErrorBoundary: this.resetErrorBoundary
85 };
86 if (typeof fallbackRender === "function") {
87 childToRender = fallbackRender(props);
88 } else if (FallbackComponent) {
89 childToRender = react.createElement(FallbackComponent, props);
90 } else if (fallback === null || react.isValidElement(fallback)) {
91 childToRender = fallback;
92 } else {
93 throw error;
94 }
95 }
96 return react.createElement(ErrorBoundaryContext.Provider, {
97 value: {
98 didCatch,
99 error,
100 resetErrorBoundary: this.resetErrorBoundary
101 }
102 }, childToRender);
103 }
104}
105function hasArrayChanged() {
106 let a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
107 let b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
108 return a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]));
109}
110
111function assertErrorBoundaryContext(value) {
112 if (value == null || typeof value.didCatch !== "boolean" || typeof value.resetErrorBoundary !== "function") {
113 throw new Error("ErrorBoundaryContext not found");
114 }
115}
116
117function useErrorBoundary() {
118 const context = react.useContext(ErrorBoundaryContext);
119 assertErrorBoundaryContext(context);
120 const [state, setState] = react.useState({
121 error: null,
122 hasError: false
123 });
124 const memoized = react.useMemo(() => ({
125 resetBoundary: () => {
126 context.resetErrorBoundary();
127 setState({
128 error: null,
129 hasError: false
130 });
131 },
132 showBoundary: error => setState({
133 error,
134 hasError: true
135 })
136 }), [context.resetErrorBoundary]);
137 if (state.hasError) {
138 throw state.error;
139 }
140 return memoized;
141}
142
143function withErrorBoundary(component, errorBoundaryProps) {
144 const Wrapped = react.forwardRef((props, ref) => react.createElement(ErrorBoundary, errorBoundaryProps, react.createElement(component, {
145 ...props,
146 ref
147 })));
148
149 // Format for display in DevTools
150 const name = component.displayName || component.name || "Unknown";
151 Wrapped.displayName = "withErrorBoundary(".concat(name, ")");
152 return Wrapped;
153}
154
155exports.ErrorBoundary = ErrorBoundary;
156exports.ErrorBoundaryContext = ErrorBoundaryContext;
157exports.useErrorBoundary = useErrorBoundary;
158exports.withErrorBoundary = withErrorBoundary;