ErrorBoundary é uma ferramenta magnífica para capturar erros gerados pelos componentes do React. Você pode fornecer mensagens de erro personalizadas de acordo com a natureza e o local do erro em si. Mas nem todos os erros lançados são tratados pelo ErrorBoundary! O que você faz com isso?
Ao considerar erros assíncronos e erros gerados fora do React, o ErrorBoundary fica aquém. Para mitigar isso, criei em meus aplicativos o que chamo de GlobalErrorHandler. Um componente funcional que simplesmente A) Abre uma caixa de diálogo de erro, informando ao usuário que algo deu errado, B) Registra o erro no servidor, para que possamos investigar e encontrar soluções.
A ideia é simples. Queremos um GlobalErrorHandler na raiz da nossa aplicação. Este manipulador deve apenas lidar com erros não detectados pelo ErrorBoundary . Além disso, deve ser facilmente descartado pelo usuário e devemos assumir que o aplicativo ainda pode ser usado.
Então a estratégia é esta: O GlobalErrorHandler não faz absolutamente nada, exceto renderizar seus filhos, por padrão. Porém, ele configura dois ouvintes de eventos, ouvindo todos os eventos de erro e rejeição não tratada no navegador. Em seguida, ele examina o erro e verifica se ele já foi tratado por algum ErrorBoundaries. Finalmente, se esse não for o caso, uma caixa de diálogo aparece, informando ao usuário que algo deu errado em algum lugar, e permite que o usuário ignore a caixa de diálogo e continue usando o aplicativo.
Antes de incomodar os usuários finais com caixas de diálogo desnecessárias ALÉM do tratamento feito pelo ErrorBoundary, primeiro temos que começar perguntando o erro: Você já foi tratado? Minha solução para isso é introduzir um novo campo no objeto de erro isHandledByBoundary. Isso é definido como verdadeiro em ErrorBoundary:
componentDidCatch(error: Error, errorInfo: ErrorInfo) { (error as any).isHandledByBoundary = true; .... }
Com isso implementado em todos os componentes ErrorBoundary (e outras máquinas que lidam com erros não detectados), estamos prontos para começar a definir nosso GlobalErrorHandler.
Então podemos construir o esqueleto do nosso GlobalErrorHandler. Ele renderiza diretamente seus filhos e também renderiza um "ErrorDialog" definido em outro lugar. (Se você deseja compartilhar este componente entre aplicativos, o ErrorDialog pode ser um suporte.)
import { useState, useEffect, ReactNode } from 'react'; import { ErrorDialog } from '../Components/ErrorDialog'; type Props = { children: ReactNode; }; export function GlobalErrorHandler({ children }: Props) { const [error, setError] = useState(null); const [isDialogOpen, setDialogOpen] = useState(false); useEffect(() => { .... }, []); function handleCloseDialog() { setDialogOpen(false); setError(null); } return ( {children} {isDialogOpen && error && ( )} > ); }
A única coisa que falta agora é o próprio tratamento de erros, definido em useEffect.
Todo o código nesta seção deve estar localizado na função useEffect!
Primeiro definimos handleWindowError. Isso deve ser entregue ao manipulador de eventos de erro no objeto janela. Nada de misterioso aqui, mas testemunhe que o evento de erro também contém informações sobre fonte, número de linha e número de coluna. O que pode ser valioso para coletar.
Normalmente, essas informações também são encontradas no objeto de erro, mas preciso fazer mais investigações empíricas sobre isso. Talvez devêssemos sempre manter os números de linha e coluna conforme relatado pelo evento de erro? Nesse caso, também poderíamos ter um estado para isso em GlobalErrorHandler (e garantir que isso seja enviado ao registrar o erro).
function handleWindowError( message: string | Event, source?: string, lineno?: number, colno?: number, error?: Error ) { if (error && (error as any).isHandledByBoundary) { return true; } const errorMessage = error ? error : `Error: ${message} at ${source}:${lineno}:${colno}`; setError(errorMessage); setDialogOpen(true); return true; }
Também definiremos o manipulador handleUnhandledRejection. Isto é para erros que são gerados dentro de promessas, mas onde esquecemos de escrever uma cláusula .catch().
function handleUnhandledRejection(event: PromiseRejectionEvent) { setError(`Unhandled promise rejection: ${event.reason}`); setDialogOpen(true); }
Então tudo o que precisamos fazer é configurar os ouvintes e removê-los sempre que GlobalErrorHandler não for mais renderizado:
window.addEventListener('error', handleWindowError); window.addEventListener('unhandledrejection', handleUnhandledRejection); return () => { window.removeEventListener('error', handleWindowError); window.removeEventListener( 'unhandledrejection', handleUnhandledRejection ); };
As instruções de retorno são, obviamente, onde retornamos da função que estamos alimentando useEffect. Isso garante que começaremos a ouvir os eventos e a tratá-los quando o componente for renderizado, e pararemos quando o componente não for mais renderizado.
Portanto, temos um GlobalEventHandler, para lidar com aqueles erros incômodos em nosso aplicativo React que são lançados de fontes assíncronas ou de fora dos componentes do React!
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3