@@ -34,12 +34,12 @@ const stack = captureOwnerStack();
34
34
35
35
Call ` captureOwnerStack ` to get the current Owner Stack.
36
36
37
- ``` js
38
- import * as React from ' react' ;
37
+ ``` js {5,5}
38
+ import { captureOwnerStack } from ' react' ;
39
39
40
40
function Component () {
41
41
if (process .env .NODE_ENV !== ' production' ) {
42
- const ownerStack = React . captureOwnerStack ();
42
+ const ownerStack = captureOwnerStack ();
43
43
console .log (ownerStack);
44
44
}
45
45
}
@@ -68,17 +68,18 @@ The Owner Stack is different from the Component Stack available in React error h
68
68
69
69
For example, consider the following code:
70
70
71
- ``` tsx
72
- import * as React from ' react' ;
73
- import * as ReactDOMClient from ' react-dom/client' ;
71
+ <Sandpack >
72
+
73
+ ``` js src/App.js
74
+ import {Suspense } from ' react' ;
74
75
75
76
function SubComponent ({disabled}) {
76
77
if (disabled) {
77
78
throw new Error (' disabled' );
78
79
}
79
80
}
80
81
81
- function Component({label }) {
82
+ export function Component ({label}) {
82
83
return (
83
84
< fieldset>
84
85
< legend> {label}< / legend>
@@ -91,24 +92,70 @@ function Navigation() {
91
92
return null ;
92
93
}
93
94
94
- function App({children }) {
95
+ export default function App ({children}) {
95
96
return (
96
- <React. Suspense fallback = " loading..." >
97
+ < Suspense fallback= " loading..." >
97
98
< main>
98
99
< Navigation / >
99
100
{children}
100
101
< / main>
101
- </React. Suspense >
102
+ < / Suspense>
102
103
);
103
104
}
105
+ ```
104
106
105
- createRoot (document .createElement (' div' )).render (
107
+ ``` js src/index.js
108
+ import {captureOwnerStack } from ' react' ;
109
+ import {createRoot } from ' react-dom/client' ;
110
+ import App , {Component } from ' ./App.js' ;
111
+ import ' ./styles.css' ;
112
+
113
+ createRoot (document .createElement (' div' ), {
114
+ onUncaughtError : (error , errorInfo ) => {
115
+ // The stacks are logged instead of showing them in the UI directly to highlight that browsers will apply sourcemaps to the logged stacks.
116
+ // Note that sourcemapping is only applied in the real browser console not in the fake one displayed on this page.
117
+ console .log (errorInfo .componentStack );
118
+ console .log (captureOwnerStack ());
119
+ },
120
+ }).render (
106
121
< App>
107
122
< Component label= " disabled" / >
108
123
< / App>
109
124
);
110
125
```
111
126
127
+ ``` json package.json hidden
128
+ {
129
+ "dependencies" : {
130
+ "react" : " experimental" ,
131
+ "react-dom" : " experimental" ,
132
+ "react-scripts" : " latest"
133
+ },
134
+ "scripts" : {
135
+ "start" : " react-scripts start" ,
136
+ "build" : " react-scripts build" ,
137
+ "test" : " react-scripts test --env=jsdom" ,
138
+ "eject" : " react-scripts eject"
139
+ }
140
+ }
141
+ ```
142
+
143
+ ``` html public/index.html hidden
144
+ <!DOCTYPE html>
145
+ <html lang =" en" >
146
+ <head >
147
+ <meta charset =" UTF-8" />
148
+ <meta name =" viewport" content =" width=device-width, initial-scale=1.0" />
149
+ <title >Document</title >
150
+ </head >
151
+ <body >
152
+ <p >Check the console output.</p >
153
+ </body >
154
+ </html >
155
+ ```
156
+
157
+ </Sandpack >
158
+
112
159
` SubComponent ` would throw an error.
113
160
The Component Stack of that error would be
114
161
@@ -124,47 +171,114 @@ at App
124
171
However, the Owner Stack would only read
125
172
126
173
```
127
- at SubComponent
128
174
at Component
129
175
```
130
176
131
177
Neither ` App ` nor the DOM components (e.g. ` fieldset ` ) are considered Owners in this Stack since they didn't contribute to "creating" the node containing ` SubComponent ` . ` App ` and DOM components only forwarded the node. ` App ` just rendered the ` children ` node as opposed to ` Component ` which created a node containing ` SubComponent ` via ` <SubComponent /> ` .
132
178
133
179
Neither ` Navigation ` nor ` legend ` are in the stack at all since it's only a sibling to a node containing ` <SubComponent /> ` .
134
180
181
+ ` SubComponent ` is omitted because it's already part of the callstack.
182
+
135
183
</DeepDive >
136
184
137
185
## Usage {/* usage* /}
138
186
139
187
### Expanding error stacks {/* expanding-error-stacks* /}
140
188
141
- In addition to the stack trace of the <CodeStep step ={1} >error</CodeStep > itself, you can use <CodeStep step ={2} >` captureOwnerStack ` </CodeStep > to append the Owner Stack.
189
+ In addition to the <CodeStep step ={1} >stack trace of the error</CodeStep > itself, you can use <CodeStep step ={2} >` captureOwnerStack ` </CodeStep > to append the Owner Stack.
142
190
This can help trace the error especially when the error is caused by props. The Owner Stack helps trace the flow of props.
143
191
144
- ``` jsx [[9, 15, "error"], [34, 10, "captureOwnerStack"]]
145
- import { captureOwnerStack } from ' react'
146
- import { hydrateRoot } from ' react-dom/client' ;
147
-
148
- const root = hydrateRoot (
149
- document .getElementById (' root' ),
150
- < App / > ,
151
- {
152
- onCaughtError : (error , errorInfo ) => {
153
- if (process .env .NODE_ENV !== ' production' ) {
154
- const ownerStack = captureOwnerStack ();
155
- error .stack += ownerStack;
156
- }
157
- console .error (
158
- ' Caught error' ,
159
- error,
160
- errorInfo .componentStack
161
- );
192
+
193
+ ``` js src/index.js [[1, 8, "error.stack"], [2, 7, "captureOwnerStack()"]]
194
+ import {captureOwnerStack } from ' react' ;
195
+ import {createRoot } from ' react-dom/client' ;
196
+
197
+ const root = createRoot (document .getElementById (' root' ), {
198
+ onUncaughtError : (error , errorInfo ) => {
199
+ if (process .env .NODE_ENV !== ' production' ) {
200
+ const ownerStack = captureOwnerStack ();
201
+ error .stack += ownerStack;
202
+ }
203
+
204
+ console .error (' Uncaught' , error);
205
+ },
206
+ }).render (< App / > );
207
+ ```
208
+
209
+ <Sandpack >
210
+
211
+ ``` js
212
+ function useCustomHook () {
213
+ throw new Error (' Boom!' );
214
+ }
215
+
216
+ function Component () {
217
+ useCustomHook ();
218
+ }
219
+
220
+ export default function App () {
221
+ return < Component / > ;
222
+ }
223
+ ```
224
+
225
+ ``` js src/index.js
226
+ import {captureOwnerStack } from ' react' ;
227
+ import {createRoot } from ' react-dom/client' ;
228
+ import App from ' ./App.js' ;
229
+ import ' ./styles.css' ;
230
+
231
+ const root = createRoot (document .getElementById (' root' ), {
232
+ onUncaughtError : (error , errorInfo ) => {
233
+ if (process .env .NODE_ENV !== ' production' ) {
234
+ const ownerStack = captureOwnerStack ();
235
+ error .stack =
236
+ // The stack is only split because these sandboxes don't implement ignore-listing 3rd party frames via sourcemaps.
237
+ // A framework would ignore-list stackframes from React via sourcemaps and then you could just `error.stack += ownerStack`.
238
+ // To learn more about ignore-listing see https://developer.chrome.com/docs/devtools/x-google-ignore-list
239
+ error .stack .split (' \n at react-stack-bottom-frame' )[0 ] + ownerStack;
162
240
}
241
+
242
+ // The stacks are logged instead of showing them in the UI directly to highlight that browsers will apply sourcemaps to the logged stacks.
243
+ // Note that sourcemapping is only applied in the real browser console not in the fake one displayed on this page.
244
+ console .error (' Uncaught' , error);
245
+ },
246
+ }).render (< App / > );
247
+ ```
248
+
249
+ ``` json package.json hidden
250
+ {
251
+ "dependencies" : {
252
+ "react" : " experimental" ,
253
+ "react-dom" : " experimental" ,
254
+ "react-scripts" : " latest"
255
+ },
256
+ "scripts" : {
257
+ "start" : " react-scripts start" ,
258
+ "build" : " react-scripts build" ,
259
+ "test" : " react-scripts test --env=jsdom" ,
260
+ "eject" : " react-scripts eject"
163
261
}
164
- );
165
- root .render (< App / > );
262
+ }
263
+ ```
264
+
265
+ ``` html public/index.html hidden
266
+ <!DOCTYPE html>
267
+ <html lang =" en" >
268
+ <head >
269
+ <meta charset =" UTF-8" />
270
+ <meta name =" viewport" content =" width=device-width, initial-scale=1.0" />
271
+ <title >Document</title >
272
+ </head >
273
+ <body >
274
+ <p >Check the console output.</p >
275
+ <div id =" root" ></div >
276
+ </body >
277
+ </html >
166
278
```
167
279
280
+ </Sandpack >
281
+
168
282
## Troubleshooting {/* troubleshooting* /}
169
283
170
284
### The Owner Stack is ` null ` {/* the-owner-stack-is-null* /}
0 commit comments