Skip to content

Commit 4b1f5cb

Browse files
committed
Move code into sandboxes
1 parent 267c0f5 commit 4b1f5cb

File tree

1 file changed

+147
-33
lines changed

1 file changed

+147
-33
lines changed

src/content/reference/react/captureOwnerStack.md

Lines changed: 147 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ const stack = captureOwnerStack();
3434

3535
Call `captureOwnerStack` to get the current Owner Stack.
3636

37-
```js
38-
import * as React from 'react';
37+
```js {5,5}
38+
import {captureOwnerStack} from 'react';
3939

4040
function Component() {
4141
if (process.env.NODE_ENV !== 'production') {
42-
const ownerStack = React.captureOwnerStack();
42+
const ownerStack = captureOwnerStack();
4343
console.log(ownerStack);
4444
}
4545
}
@@ -68,17 +68,18 @@ The Owner Stack is different from the Component Stack available in React error h
6868

6969
For example, consider the following code:
7070

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';
7475

7576
function SubComponent({disabled}) {
7677
if (disabled) {
7778
throw new Error('disabled');
7879
}
7980
}
8081

81-
function Component({label}) {
82+
export function Component({label}) {
8283
return (
8384
<fieldset>
8485
<legend>{label}</legend>
@@ -91,24 +92,70 @@ function Navigation() {
9192
return null;
9293
}
9394

94-
function App({children}) {
95+
export default function App({children}) {
9596
return (
96-
<React.Suspense fallback="loading...">
97+
<Suspense fallback="loading...">
9798
<main>
9899
<Navigation />
99100
{children}
100101
</main>
101-
</React.Suspense>
102+
</Suspense>
102103
);
103104
}
105+
```
104106

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(
106121
<App>
107122
<Component label="disabled" />
108123
</App>
109124
);
110125
```
111126

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+
112159
`SubComponent` would throw an error.
113160
The Component Stack of that error would be
114161

@@ -124,47 +171,114 @@ at App
124171
However, the Owner Stack would only read
125172

126173
```
127-
at SubComponent
128174
at Component
129175
```
130176

131177
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 />`.
132178

133179
Neither `Navigation` nor `legend` are in the stack at all since it's only a sibling to a node containing `<SubComponent />`.
134180

181+
`SubComponent` is omitted because it's already part of the callstack.
182+
135183
</DeepDive>
136184

137185
## Usage {/*usage*/}
138186

139187
### Expanding error stacks {/*expanding-error-stacks*/}
140188

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.
142190
This can help trace the error especially when the error is caused by props. The Owner Stack helps trace the flow of props.
143191

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;
162240
}
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"
163261
}
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>
166278
```
167279

280+
</Sandpack>
281+
168282
## Troubleshooting {/*troubleshooting*/}
169283

170284
### The Owner Stack is `null` {/*the-owner-stack-is-null*/}

0 commit comments

Comments
 (0)