18
19
import ReactSharedInternals from 'shared/ReactSharedInternals';
20
21
+import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
22
+
23
// Side-channel since I'm not sure we want to make this part of the public API
24
let componentName: null | string = null;
25
let errorBoundaryName: null | string = null;
36
// So we add those into a separate console.warn.
37
reportGlobalError(error);
38
if (__DEV__) {
37
- const componentStack =
38
- errorInfo.componentStack != null ? errorInfo.componentStack : '';
39
-
39
const componentNameMessage = componentName
41
- ? `An error occurred in the <${componentName}> component:`
42
- : 'An error occurred in one of your React components:';
40
+ ? `An error occurred in the <${componentName}> component.`
41
+ : 'An error occurred in one of your React components.';
42
44
- console['warn'](
45
- '%s\n%s\n\n%s',
46
- componentNameMessage,
47
- componentStack || '',
43
+ const errorBoundaryMessage =
44
'Consider adding an error boundary to your tree to customize error handling behavior.\n' +
49
- 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.',
50
- );
45
+ 'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.';
46
+
47
+ if (enableOwnerStacks) {
48
+ console.warn(
49
+ '%s\n\n%s\n',
50
+ componentNameMessage,
51
+ errorBoundaryMessage,
52
+ // We let our console.error wrapper add the component stack to the end.
53
+ );
54
+ } else {
55
+ // The current Fiber is disconnected at this point which means that console printing
56
+ // cannot add a component stack since it terminates at the deletion node. This is not
57
+ // a problem for owner stacks which are not disconnected but for the parent component
58
+ // stacks we need to use the snapshot we've previously extracted.
59
+ const componentStack =
60
+ errorInfo.componentStack != null ? errorInfo.componentStack : '';
61
+ // Don't transform to our wrapper
62
+ console['warn'](
63
+ '%s\n\n%s\n%s',
64
+ componentNameMessage,
65
+ errorBoundaryMessage,
66
+ componentStack,
67
+ );
68
+ }
69
}
70
}
71
81
82
// Caught by error boundary
83
if (__DEV__) {
66
- const componentStack =
67
- errorInfo.componentStack != null ? errorInfo.componentStack : '';
68
-
84
const componentNameMessage = componentName
70
- ? `The above error occurred in the <${componentName}> component:`
71
- : 'The above error occurred in one of your React components:';
85
+ ? `The above error occurred in the <${componentName}> component.`
86
+ : 'The above error occurred in one of your React components.';
87
88
// In development, we provide our own message which includes the component stack
89
// in addition to the error.
75
- // Don't transform to our wrapper
76
- console['error'](
77
- '%o\n\n%s\n%s\n\n%s',
78
- error,
79
- componentNameMessage,
80
- componentStack,
90
+ const recreateMessage =
91
`React will try to recreate this component tree from scratch ` +
82
- `using the error boundary you provided, ${
83
- errorBoundaryName || 'Anonymous'
84
- }.`,
85
- );
92
+ `using the error boundary you provided, ${
93
+ errorBoundaryName || 'Anonymous'
94
+ }.`;
95
+
96
+ if (enableOwnerStacks) {
97
+ console.error(
98
+ '%o\n\n%s\n\n%s\n',
99
+ error,
100
+ componentNameMessage,
101
+ recreateMessage,
102
+ // We let our consoleWithStackDev wrapper add the component stack to the end.
103
+ );
104
+ } else {
105
+ // The current Fiber is disconnected at this point which means that console printing
106
+ // cannot add a component stack since it terminates at the deletion node. This is not
107
+ // a problem for owner stacks which are not disconnected but for the parent component
108
+ // stacks we need to use the snapshot we've previously extracted.
109
+ const componentStack =
110
+ errorInfo.componentStack != null ? errorInfo.componentStack : '';
111
+ // Don't transform to our wrapper
112
+ console['error'](
113
+ '%o\n\n%s\n\n%s\n%s',
114
+ error,
115
+ componentNameMessage,
116
+ recreateMessage,
117
+ componentStack,
118
+ );
119
+ }
120
} else {
121
// In production, we print the error directly.
122
// This will include the message, the JS stack, and anything the browser wants to show.
123
// We pass the error object instead of custom message so that the browser displays the error natively.
90
- console['error'](error); // Don't transform to our wrapper
124
+ console['error'](error); // Don't transform to our wrapper, however, React DevTools can still add a stack.
125
}
126
}
127