Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
import { Component, type ErrorInfo, type ReactNode } from "react";
class ErrorBoundary extends Component<
{ children: ReactNode; fallback: ReactNode },
{ hasError: boolean }
> {
state = { hasError: false };
static getDerivedStateFromError(): { hasError: boolean } {
return { hasError: true };
}
componentDidCatch(error: Error, info: ErrorInfo) {
console.error("ErrorBoundary caught:", error, info.componentStack);
}
render() {
if (this.state.hasError) return this.props.fallback;
return this.props.children;
}
}
// Uso
<ErrorBoundary fallback={<p>Algo deu errado.</p>}>
<RiskyComponent />
</ErrorBoundary>Quando usar isso: Envolva qualquer subárvore de componente que possa lançar um erro durante a renderização. Essencial em torno de componentes de busca de dados, widgets de terceiros, renderizadores de conteúdo gerado pelo usuário e layouts de nível de rota.
import {
Component,
useState,
useCallback,
type ErrorInfo,
type ReactNode,
} from "react";
// --- Error boundary completo com recuperação ---
interface ErrorBoundaryProps {
children: ReactNode;
fallback?: ReactNode;
onError?: (error: Error, info: ErrorInfo) => void;
renderFallback?: (props: {
error: Error;
reset: () => void;
}) => ReactNode;
resetKeys?: unknown[];
}
interface ErrorBoundaryState {
error: Error | null;
}
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
state: ErrorBoundaryState = { error: null };
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
this.props.onError?.(error, info);
}
componentDidUpdate(prevProps: ErrorBoundaryProps) {
if (this.state.error && prevProps.resetKeys !== this.props.resetKeys) {
// Se resetKeys mudou, tente a recuperação
const changed = this.props.resetKeys?.some(
(key, i) => key !== prevProps.resetKeys?.[i]
);
if (changed) this.reset();
}
}
reset = () => {
this.setState({ error: null });
};
render() {
const { error } = this.state;
const { children, fallback, renderFallback } = this.props;
if (error) {
if (renderFallback) {
return renderFallback({ error, reset: this.reset });
}
return fallback ?? <p>Algo deu errado.</p>;
}
return children;
}
}
// --- Uso com UI de fallback e recuperação ---
function UserProfile({ userId }: { userId: string }) {
return (
<ErrorBoundary
resetKeys={[userId]}
onError={(error) => {
// Reportar para serviço de rastreamento de erros
reportToSentry(error);
}}
renderFallback={({ error, reset }) => (
<div className="p-6 bg-red-50 rounded-lg text-center">
<h3 className="text-red-800 font-semibold">Falha ao carregar perfil</h3>
<p className="text-red-600 mt-2">{error.message}</p>
<button
onClick={reset}
className="mt-4 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700"
>
Tentar Novamente
</button>
</div>
)}
>
<ProfileContent userId={userId} />
</ErrorBoundary>
);
}
// --- Error boundaries granulares por seção ---
function DashboardPage() {
return (
<div className="grid grid-cols-2 gap-4">
<ErrorBoundary fallback={<WidgetError name="Receita" />}>
<RevenueChart />
</ErrorBoundary>
<ErrorBoundary fallback={<WidgetError name="Usuários" />}>
<UserStats />
</ErrorBoundary>
<ErrorBoundary fallback={<WidgetError name="Atividade" />}>
<ActivityFeed />
</ErrorBoundary>
</div>
);
}
function WidgetError({ name }: { name: string }) {
return (
<div className="p-4 border border-red-200 rounded bg-red-50 text-red-700">
Widget {name} falhou ao carregar.
</div>
);
}O que isso demonstra:
resetKeys que reseta automaticamente o boundary quando as dependências mudam (por exemplo, parâmetros de rota).onError) para Sentry ou serviços similares.static getDerivedStateFromError() ou componentDidCatch().getDerivedStateFromError é executado durante a renderização para definir o estado de erro e acionar a UI de fallback.componentDidCatch é executado após o commit para efeitos colaterais como o registro de erros.| Método de Ciclo de Vida | Quando Chamado | Propósito |
|---|---|---|
getDerivedStateFromError(error) | Durante a renderização | Retorna novo estado para acionar a UI de fallback |
componentDidCatch(error, info) | Após o commit | Efeitos colaterais: logging, relatórios de erro |
info.componentStack | Em componentDidCatch | String mostrando o caminho da árvore de componentes |
Wrapper de error boundary baseado em hook - use um pacote ou um wrapper fino para ergonomia de hook:
// Com react-error-boundary (biblioteca popular)
import { ErrorBoundary } from "react-error-boundary";
function App() {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onReset={() => queryClient.invalidateQueries()}
resetKeys={[routeKey]}
>
<AppContent />
</ErrorBoundary>
);
}
function ErrorFallback({
error,
resetErrorBoundary,
}: {
error: Error;
resetErrorBoundary: () => void;
}) {
return (
<div role="alert">
<p>Erro: {error.message}</p>
<button onClick={resetErrorBoundary}>Tentar Novamente</button>
</div>
);
}Boundaries aninhados com granularidade diferente:
// Boundary de nível de página captura tudo
<ErrorBoundary fallback={<FullPageError />}>
<Layout>
{/* Boundaries de nível de seção isolam falhas */}
<ErrorBoundary fallback={<SectionError />}>
<Sidebar />
</ErrorBoundary>
<ErrorBoundary fallback={<SectionError />}>
<MainContent />
</ErrorBoundary>
</Layout>
</ErrorBoundary>{ error: Error | null } em vez de { hasError: boolean } para preservar o objeto de erro para o fallback.ErrorInfo do React para o segundo parâmetro de componentDidCatch.componentStack em ErrorInfo é uma string, não um objeto estruturado.Erros de manipulador de eventos não são capturados - Error boundaries capturam apenas erros durante a renderização do React. Um onClick que lança um erro não será capturado. Correção: Use try/catch em manipuladores de eventos e defina o estado de erro local.
Erros assíncronos não são capturados - Promises que rejeitam dentro de useEffect ou manipuladores de eventos não são capturadas. Correção: Capture erros assíncronos e defina o estado local ou relance durante a renderização (por exemplo, armazene no estado e lance na renderização).
Sem error boundaries baseados em hook - O React não fornece um equivalente de hook para getDerivedStateFromError. Correção: Use o padrão de componente de classe ou a biblioteca react-error-boundary.
O próprio error boundary lançando erro - Se o método de renderização do próprio error boundary lançar um erro, ele se propagará para o boundary pai mais próximo. Correção: Mantenha os métodos de renderização do error boundary simples. Nunca lance um erro na UI de fallback.
Recuperação sem desmontagem - Redefinir hasError para false sem remontar os filhos pode deixá-los em um estado quebrado. Correção: Use uma prop key no wrapper dos filhos para forçar a remontagem no reset.
| Abordagem | Trade-off |
|---|---|
| Error boundaries | Captura erros de renderização; requer componente de classe |
react-error-boundary | API amigável a hooks, resetKeys; dependência extra |
| Try/catch em manipuladores de eventos | Manual; não captura erros de renderização |
| Suspense com tratamento de erros | Lida com erros de carregamento assíncrono através de promises lançadas |
window.onerror global | Captura erros não capturados; sem recuperação específica do React |
De uma aplicação SaaS de produção Next.js 15 / React 19 (SystemsArchitect.io).
// Exemplo de produção: Next.js error.tsx com logging, retry e fallback de recarregamento de página inteira
// Arquivo: app/error.tsx
'use client';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Registrar em serviço de rastreamento de erros externo
console.error('Erro na aplicação:', error);
// reportToSentry(error);
}, [error]);
return (
<div className="flex min-h-screen items-center justify-center">
<div className="text-center space-y-4">
<h2 className="text-2xl font-bold">Algo deu errado</h2>
{error.digest && (
<p className="text-sm text-gray-500">ID do Erro: {error.digest}</p>
)}
<div className="flex gap-3 justify-center">
<button
onClick={reset}
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
>
Tentar novamente
</button>
<button
onClick={() => window.location.href = '/'}
className="px-4 py-2 border rounded hover:bg-gray-50"
>
Ir para a página inicial
</button>
</div>
</div>
</div>
);
}O que isso demonstra em produção:
error.tsx é uma convenção do Next.js App Router que envolve automaticamente a página em um error boundary. Você não precisa escrever um error boundary baseado em classe.useEffect registra o erro ao montar. Este é o local correto para enviar erros para Sentry ou um serviço similar. Não registre no corpo da renderização porque ele é executado durante a fase de renderização do React.reset() re-renderiza o segmento da rota, o que tenta novamente o componente falho. Isso funciona bem para erros transitórios como falhas de rede ou condições de corrida.error.digest é um identificador de erro hasheado que o Next.js gera para erros do lado do servidor. É seguro exibi-lo aos usuários (não expõe stack traces ou detalhes sensíveis). Em desenvolvimento, o erro completo é exibido em vez disso.window.location.href em vez de router.push() como uma escolha deliberada. Se o erro corrompeu a árvore do React ou o estado do roteador do lado do cliente, router.push() pode falhar ou renderizar a mesma página quebrada. Um recarregamento completo da página via window.location.href garante um início limpo.error.tsx deve ser um Client Component ('use client'). Error boundaries requerem React do lado do cliente para capturar e recuperar de erros.getDerivedStateFromError ou componentDidCatch.react-error-boundary se preferir uma API wrapper amigável a hooks.getDerivedStateFromError é executado durante a fase de renderização para atualizar o estado e acionar a UI de fallback. Deve ser uma função pura.componentDidCatch é executado após a fase de commit para efeitos colaterais como o registro de erros no Sentry.<ErrorBoundary
resetKeys={[userId]}
renderFallback={({ error, reset }) => (
<div>
<p>{error.message}</p>
<button onClick={reset}>Tentar Novamente</button>
</div>
)}
>
<ProfileContent userId={userId} />
</ErrorBoundary>resetKeys mudam (por exemplo, userId muda), o boundary reseta automaticamente e tenta renderizar novamente.onClick que lança um erro não interrompe a renderização; ele lança na event loop do navegador.interface ErrorBoundaryState {
error: Error | null;
}
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
state: ErrorBoundaryState = { error: null };
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { error };
}
}{ error: Error | null } para preservar o objeto de erro para o fallback.ErrorInfo do React para o segundo parâmetro de componentDidCatch.error.digest é um identificador de erro hasheado gerado pelo Next.js para erros do lado do servidor.router.push() pode falhar ou renderizar a mesma página quebrada.window.location.href aciona um recarregamento completo da página, garantindo um início limpo.hasError para false re-renderiza os mesmos filhos, que podem ainda estar quebrados.key no wrapper dos filhos para forçar uma desmontagem e remontagem completas no reset.childrenRevisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥