Skip to content

Commit 71c8dd9

Browse files
committed
Reference docs for captureOwnerStack
1 parent 9000e6e commit 71c8dd9

File tree

2 files changed

+186
-2
lines changed

2 files changed

+186
-2
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
---
2+
title: captureOwnerStack
3+
---
4+
5+
<Wip>
6+
7+
**This API is experimental and is not available in a stable version of React yet.**
8+
9+
You can try it by upgrading React packages to the most recent experimental version:
10+
11+
- `react@experimental`
12+
13+
Experimental versions of React may contain bugs. Don't use them in production.
14+
15+
</Wip>
16+
17+
<Intro>
18+
19+
`captureOwnerStack` reads the current **owner** Component stack and returns it as a string.
20+
If no owner stack is available, it returns an empty string.
21+
22+
```js
23+
captureOwnerStack();
24+
```
25+
26+
</Intro>
27+
28+
<InlineToc />
29+
30+
---
31+
32+
## Reference {/*reference*/}
33+
34+
### `captureOwnerStack()` {/*captureownerstack*/}
35+
36+
Call `captureOwnerStack` to get the current owner Component stack.
37+
38+
```js
39+
import * as React from 'react';
40+
41+
function Component() {
42+
if (process.env.NODE_ENV !== 'production') {
43+
const ownerStack = React.captureOwnerStack();
44+
console.log(ownerStack);
45+
}
46+
}
47+
```
48+
49+
#### Parameters {/*parameters*/}
50+
51+
`captureOwnerStack` does not take any parameters.
52+
53+
#### Returns {/*returns*/}
54+
55+
`captureOwnerStack` returns `string`.
56+
57+
#### Caveats {/*caveats*/}
58+
59+
`captureOwnerStack` is only available in development builds of React.
60+
In production builds, the `captureOwnerStack` export does not exist.
61+
62+
Only call `captureOwnerStack` in development environments:
63+
64+
```tsx
65+
// Use a namespace import to avoid errors in production when using ES modules.
66+
// Non-existing exports throw a `SyntaxError` in ES modules.
67+
import * as React from 'react';
68+
69+
let ownerStack = '';
70+
if (process.env.NODE_ENV !== 'prodction') {
71+
ownerStack = React.captureOwnerStack();
72+
}
73+
```
74+
75+
## Owner Component stacks vs parent Component stacks {/*owner-component-stacks-vs-parent-component-stacks*/}
76+
77+
The owner Component stack is different from the **parent** Component stack available error handlers like [`errorInfo.componentStack` in `onUncaughtError`](http://localhost:3000/reference/react-dom/client/hydrateRoot#show-a-dialog-for-uncaught-errors).
78+
79+
For example, consider the following code:
80+
81+
```tsx
82+
import * as React from 'react';
83+
import * as ReactDOMClient from 'react-dom/client';
84+
85+
function SubComponent({disabled}) {
86+
if (disabled) {
87+
throw new Error('disabled');
88+
}
89+
}
90+
91+
function Component({label}) {
92+
return (
93+
<fieldset>
94+
<legend>{label}</legend>
95+
<SubComponent key={label} disabled={label === 'disabled'} />
96+
</fieldset>
97+
);
98+
}
99+
100+
function Navigation() {
101+
return null;
102+
}
103+
104+
function App({children}) {
105+
return (
106+
<React.Suspense fallback="loading...">
107+
<main>
108+
<Navigation />
109+
{children}
110+
</main>
111+
</React.Suspense>
112+
);
113+
}
114+
115+
createRoot(document.createElement('div')).render(
116+
<App>
117+
<Component label="disabled" />
118+
</App>
119+
);
120+
```
121+
122+
`SubComponent` would throw an error.
123+
The **parent** component stack of that error would be
124+
125+
```
126+
at SubComponent
127+
at fieldset
128+
at Component
129+
at main
130+
at React.Suspense
131+
at App
132+
```
133+
134+
However, the owner stack would only read
135+
136+
```
137+
at SubComponent
138+
at Component
139+
```
140+
141+
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 />`.
142+
143+
Neither `Navigation` nor `legend` are in the stack at all since it's only a sibling to a node containing `<SubComponent />`.
144+
145+
### When to use which {/*when-to-use-which*/}
146+
147+
The parent stack is useful for contextual information e.g. [`React.Suspense`](/reference/react/Suspense), [React Context](https://react.dev/reference/react/createContext), or [`<form>`](/reference/react-dom/components/form).
148+
149+
The owner stack is useful for tracing the flow of props. Owner stacks are equivalent to [call stacks](https://developer.mozilla.org/en-US/docs/Glossary/Call_stack) if all JSX would be converted to direct function calls e.g. `Component({label: "disabled"})` instead of `<Component label="disabled" />`.
150+
151+
## Usage {/*usage*/}
152+
153+
### Expanding error stacks {/*expanding-error-stacks*/}
154+
155+
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 stack trace of the owner Component.
156+
This can help trace the error especially when the error is caused by props. The owner Component stack helps trace the flow of props.
157+
158+
```jsx [[9, 15, "error"], [34, 10, "captureOwnerStack"]]
159+
import * as React from 'react'
160+
import { hydrateRoot } from 'react-dom/client';
161+
162+
const root = hydrateRoot(
163+
document.getElementById('root'),
164+
<App />,
165+
{
166+
onCaughtError: (error, errorInfo) => {
167+
if (process.env.NODE_ENV !== 'production') {
168+
const ownerStack = React.captureOwnerStack();
169+
error.stack += ownerStack;
170+
}
171+
console.error(
172+
'Caught error',
173+
error,
174+
errorInfo.componentStack
175+
);
176+
}
177+
}
178+
);
179+
root.render(<App />);
180+
```

src/sidebarReference.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@
147147
"title": "experimental_taintUniqueValue",
148148
"path": "/reference/react/experimental_taintUniqueValue",
149149
"version": "canary"
150+
},
151+
{
152+
"title": "captureOwnerStack",
153+
"path": "/reference/react/captureOwnerStack",
154+
"version": "canary"
150155
}
151156
]
152157
},
@@ -304,7 +309,6 @@
304309
"title": "prerenderToNodeStream",
305310
"path": "/reference/react-dom/static/prerenderToNodeStream"
306311
}
307-
308312
]
309313
},
310314
{
@@ -398,4 +402,4 @@
398402
]
399403
}
400404
]
401-
}
405+
}

0 commit comments

Comments
 (0)