captureOwnerStack 在开发中读取当前的所有者堆栈,并在可用时将其作为字符串返回。
const stack = captureOwnerStack();参考
🌐 Reference
captureOwnerStack()
调用 captureOwnerStack 以获取当前的所有者堆栈。
🌐 Call captureOwnerStack to get the current Owner Stack.
import * as React from 'react';
function Component() {
if (process.env.NODE_ENV !== 'production') {
const ownerStack = React.captureOwnerStack();
console.log(ownerStack);
}
}参数
🌐 Parameters
captureOwnerStack不接受任何参数。
返回
🌐 Returns
captureOwnerStack 返回 string | null。
Owner Stacks 可用于
🌐 Owner Stacks are available in
- 组件渲染
- 效果(例如
useEffect) - React 的事件处理器(例如
<button onClick={...} />) - React 错误处理器(React 根选项
onCaughtError、onRecoverableError和onUncaughtError)
如果没有可用的所有者堆栈,将返回 null(参见 疑难解答:所有者堆栈是 null)。
🌐 If no Owner Stack is available, null is returned (see Troubleshooting: The Owner Stack is null).
注意事项
🌐 Caveats
- Owner Stacks 仅在开发中可用。在开发环境之外,
captureOwnerStack将始终返回null。
深入研究
🌐 Owner Stack vs Component Stack
Owner 堆栈不同于在 React 错误处理器中可用的 Component 堆栈,例如 errorInfo.componentStack 在 onUncaughtError。
🌐 The Owner Stack is different from the Component Stack available in React error handlers like errorInfo.componentStack in onUncaughtError.
例如,请考虑以下代码:
🌐 For example, consider the following code:
import {captureOwnerStack} from 'react'; import {createRoot} from 'react-dom/client'; import App, {Component} from './App.js'; import './styles.css'; createRoot(document.createElement('div'), { onUncaughtError: (error, errorInfo) => { // The stacks are logged instead of showing them in the UI directly to // highlight that browsers will apply sourcemaps to the logged stacks. // Note that sourcemapping is only applied in the real browser console not // in the fake one displayed on this page. // Press "fork" to be able to view the sourcemapped stack in a real console. console.log(errorInfo.componentStack); console.log(captureOwnerStack()); }, }).render( <App> <Component label="disabled" /> </App> );
SubComponent 会抛出一个错误。
该错误的组件堆栈将是
at SubComponent
at fieldset
at Component
at main
at React.Suspense
at App但是,所有者堆栈只会读取
🌐 However, the Owner Stack would only read
at Component在这个 Stack 中,既不是 App,也不是 DOM 组件(例如 fieldset)被视为 Owners,因为它们没有参与“创建”包含 SubComponent 的节点。App 和 DOM 组件只是转发了该节点。App 只是渲染了 children 节点,而不是 Component,后者通过 <SubComponent /> 创建了包含 SubComponent 的节点。
🌐 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 />.
Navigation 和 legend 都完全不在栈中,因为它们只是包含 <SubComponent /> 的节点的兄弟节点。
🌐 Neither Navigation nor legend are in the stack at all since it’s only a sibling to a node containing <SubComponent />.
SubComponent 被省略,因为它已经是调用堆栈的一部分。
用法
🌐 Usage
增强自定义错误覆盖
🌐 Enhance a custom error overlay
import { captureOwnerStack } from "react";
import { instrumentedConsoleError } from "./errorOverlay";
const originalConsoleError = console.error;
console.error = function patchedConsoleError(...args) {
originalConsoleError.apply(console, args);
const ownerStack = captureOwnerStack();
onConsoleError({
// Keep in mind that in a real application, console.error can be
// called with multiple arguments which you should account for.
consoleMessage: args[0],
ownerStack,
});
};如果你拦截 console.error 调用以在错误覆盖中高亮它们,你可以调用 captureOwnerStack 来包含所有者堆栈。
🌐 If you intercept console.error calls to highlight them in an error overlay, you can call captureOwnerStack to include the Owner Stack.
import { captureOwnerStack } from "react"; import { createRoot } from "react-dom/client"; import App from './App'; import { onConsoleError } from "./errorOverlay"; import './styles.css'; const originalConsoleError = console.error; console.error = function patchedConsoleError(...args) { originalConsoleError.apply(console, args); const ownerStack = captureOwnerStack(); onConsoleError({ // Keep in mind that in a real application, console.error can be // called with multiple arguments which you should account for. consoleMessage: args[0], ownerStack, }); }; const container = document.getElementById("root"); createRoot(container).render(<App />);
故障排除
🌐 Troubleshooting
所有者堆栈是 null
🌐 The Owner Stack is null
captureOwnerStack 的调用发生在 React 控制函数之外,例如在 setTimeout 回调中、在 fetch 调用之后或在自定义 DOM 事件处理程序中。在渲染、Effect、React 事件处理程序和 React 错误处理程序(例如 hydrateRoot#options.onCaughtError)期间,Owner Stack 应该是可用的。
🌐 The call of captureOwnerStack happened outside of a React controlled function e.g. in a setTimeout callback, after a fetch call or in a custom DOM event handler. During render, Effects, React event handlers, and React error handlers (e.g. hydrateRoot#options.onCaughtError) Owner Stacks should be available.
在下面的示例中,点击按钮将记录一个空的所有者堆栈,因为 captureOwnerStack 是在自定义 DOM 事件处理程序中调用的。必须更早捕获所有者堆栈,例如通过将 captureOwnerStack 的调用移到 Effect 体内。
import {captureOwnerStack, useEffect} from 'react'; export default function App() { useEffect(() => { // Should call `captureOwnerStack` here. function handleEvent() { // Calling it in a custom DOM event handler is too late. // The Owner Stack will be `null` at this point. console.log('Owner Stack: ', captureOwnerStack()); } document.addEventListener('click', handleEvent); return () => { document.removeEventListener('click', handleEvent); } }) return <button>Click me to see that Owner Stacks are not available in custom DOM event handlers</button>; }
captureOwnerStack 不可用
🌐 captureOwnerStack is not available
captureOwnerStack 仅在开发版本中导出。在生产版本中,它将是 undefined。如果在为生产和开发打包的文件中使用 captureOwnerStack,你应该有条件地从命名空间导入中访问它。
// Don't use named imports of `captureOwnerStack` in files that are bundled for development and production.
import {captureOwnerStack} from 'react';
// Use a namespace import instead and access `captureOwnerStack` conditionally.
import * as React from 'react';
if (process.env.NODE_ENV !== 'production') {
const ownerStack = React.captureOwnerStack();
console.log('Owner Stack', ownerStack);
}