captureOwnerStack
captureOwnerStack
は、開発環境で現在のオーナスタック (Owner Stack) を読み取り、利用可能な場合は文字列として返します。
const stack = captureOwnerStack();
リファレンス
captureOwnerStack()
captureOwnerStack
を呼び出して、現在のオーナスタックを取得します。
import * as React from 'react';
function Component() {
if (process.env.NODE_ENV !== 'production') {
const ownerStack = React.captureOwnerStack();
console.log(ownerStack);
}
}
引数
captureOwnerStack
は引数を受け取りません。
返り値
captureOwnerStack
は string | null
を返します。
オーナスタックは、以下の状況で利用できます。
- コンポーネントのレンダー中
- エフェクト(
useEffect
など)内 - React のイベントハンドラ内(
<button onClick={...} />
など) - React のエラーハンドラ(React ルートオプション の
onCaughtError
、onRecoverableError
、onUncaughtError
など)
オーナスタックが利用できない場合は null
が返されます(トラブルシューティング:オーナスタックが null
になる を参照)。
注意点
- オーナスタックは開発環境でのみ利用できます。開発環境以外では
captureOwnerStack
は常にnull
を返します。
さらに深く知る
オーナスタックは、React のエラーハンドラで利用できるコンポーネントスタック(例:onUncaughtError
内での errorInfo.componentStack
)とは異なります。
例えば、次のコードを考えてみましょう。
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
一方、オーナスタックは次のようになります。
at Component
このスタックでは、App
や DOM コンポーネント(例:fieldset
)は「オーナ」扱いとなりません。それらは SubComponent
を「作成」したわけではなく、ノードを単に転送しただけだからです。Component
は <SubComponent />
というマークアップを通じて SubComponent
ノードを作成しているのに対し、App
は children
を単にレンダーしているだけです。
また、Navigation
や legend
も、<SubComponent />
を含むノードの兄弟であるためスタックには含まれません。
SubComponent
はすでにコールスタックに含まれているため、オーナスタックには表示されません。
使用法
カスタムのエラーオーバーレイの機能強化
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
を呼び出してオーナスタックを含めることができます。
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 />);
トラブルシューティング
オーナスタックが null
になる
captureOwnerStack
の呼び出しが React 管理外の関数(setTimeout
のコールバック、fetch
の後、カスタム DOM イベントハンドラなど)で行われています。レンダー中、エフェクト内、React 管理のイベントハンドラやエラーハンドラ(例:hydrateRoot#options.onCaughtError
)内では、オーナスタックが利用できるはずです。
以下の例では、captureOwnerStack
の呼び出しがカスタム DOM イベントハンドラ内で行われているため、ボタンをクリックしてもログに出力されるオーナスタックは空になります。オーナスタックの取得は、呼び出しをエフェクト本体に移動するなどして先に取得しておく必要があります。
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
は開発ビルドでのみエクスポートされます。本番ビルドでは 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);
}