captureOwnerStack

captureOwnerStack lê a Pilha de Proprietários (Owner Stack) atual em desenvolvimento e a retorna como uma string, se disponível.

const stack = captureOwnerStack();

Referência

captureOwnerStack()

Chame captureOwnerStack para obter a Pilha de Proprietários atual.

import * as React from 'react';

function Component() {
if (process.env.NODE_ENV !== 'production') {
const ownerStack = React.captureOwnerStack();
console.log(ownerStack);
}
}

Parâmetros

captureOwnerStack não aceita parâmetros.

Retorna

captureOwnerStack retorna string | null.

As Pilhas de Proprietários estão disponíveis em:

  • Renderização de componentes
  • Efeitos (ex: useEffect)
  • Manipuladores de eventos do React (ex: <button onClick={...} />)
  • Manipuladores de erros do React (Opções do Root do React onCaughtError, onRecoverableError e onUncaughtError)

Se nenhuma Pilha de Proprietários estiver disponível, null será retornado (veja Solução de Problemas: A Pilha de Proprietários é null).

Ressalvas

  • As Pilhas de Proprietários estão disponíveis apenas em desenvolvimento. captureOwnerStack sempre retornará null fora do ambiente de desenvolvimento.
Deep Dive

Pilha de Proprietários vs. Pilha de Componentes

A Pilha de Proprietários é diferente da Pilha de Componentes disponível em manipuladores de erros do React, como errorInfo.componentStack em onUncaughtError.

Por exemplo, considere o seguinte código:

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) => {
    // As pilhas são registradas em log em vez de serem exibidas diretamente na UI para
    // destacar que os navegadores aplicarão sourcemaps às pilhas registradas em log.
    // Observe que o sourcemapping é aplicado apenas no console real do navegador, não
    // no console falso exibido nesta página.
    // Pressione "fork" para poder visualizar a pilha com sourcemap em um console real.
    console.log(errorInfo.componentStack);
    console.log(captureOwnerStack());
  },
}).render(
  <App>
    <Component label="disabled" />
  </App>
);

SubComponent lançaria um erro. A Pilha de Componentes desse erro seria:

at SubComponent
at fieldset
at Component
at main
at React.Suspense
at App

No entanto, a Pilha de Proprietários leria apenas:

at Component

Nem App nem os componentes DOM (ex: fieldset) são considerados Proprietários nesta Pilha, pois não contribuíram para “criar” o nó que contém SubComponent. App e os componentes DOM apenas encaminharam o nó. App apenas renderizou o nó children, em contraste com Component, que criou um nó contendo SubComponent através de <SubComponent />.

Nem Navigation nem legend estão na pilha, pois são apenas irmãos de um nó que contém <SubComponent />.

SubComponent é omitido porque já faz parte da pilha de chamadas.

Uso

Aprimorar um overlay de erro personalizado

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({
// Lembre-se que em uma aplicação real, console.error pode ser
// chamado com múltiplos argumentos que você deve considerar.
consoleMessage: args[0],
ownerStack,
});
};

Se você interceptar chamadas de console.error para destacá-las em um overlay de erro, você pode chamar captureOwnerStack para incluir a Pilha de Proprietários.

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 />);

Solução de Problemas

A Pilha de Proprietários é null

A chamada de captureOwnerStack ocorreu fora de uma função controlada pelo React, por exemplo, em um callback de setTimeout, após uma chamada fetch ou em um manipulador de eventos DOM personalizado. Durante a renderização, Efeitos, manipuladores de eventos do React e manipuladores de erros do React (ex: hydrateRoot#options.onCaughtError), as Pilhas de Proprietários devem estar disponíveis.

No exemplo abaixo, clicar no botão registrará uma Pilha de Proprietários vazia porque captureOwnerStack foi chamado durante um manipulador de eventos DOM personalizado. A Pilha de Proprietários deve ser capturada anteriormente, por exemplo, movendo a chamada de captureOwnerStack para o corpo do Efeito.

import {captureOwnerStack, useEffect} from 'react';

export default function App() {
  useEffect(() => {
    // Deveria chamar `captureOwnerStack` aqui.
    function handleEvent() {
      // Chamá-la em um manipulador de eventos DOM personalizado é tarde demais.
      // A Pilha de Proprietários será `null` neste ponto.
      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 não está disponível

captureOwnerStack é exportado apenas em builds de desenvolvimento. Será undefined em builds de produção. Se captureOwnerStack for usado em arquivos que são empacotados para produção e desenvolvimento, você deve acessá-lo condicionalmente a partir de uma importação de namespace.

// Não use importações nomeadas de `captureOwnerStack` em arquivos que são empacotados para desenvolvimento e produção.
import {captureOwnerStack} from 'react';
// Use uma importação de namespace em vez disso e acesse `captureOwnerStack` condicionalmente.
import * as React from 'react';

if (process.env.NODE_ENV !== 'production') {
const ownerStack = React.captureOwnerStack();
console.log('Owner Stack', ownerStack);
}