Os erros são uma parte inevitável do desenvolvimento. Eles sempre parecem surgir nos momentos mais inoportunos para garantir que nossos aplicativos não funcionem como esperado. Independentemente de como eles encontram seu caminho em nosso código, o tratamento de erros é o antídoto para esses confusos de desenvolvimento não intencionais, mais conhecidos como exceções.

Em JavaScript normal, a instrução try… catch oferece uma API com a qual podemos tentar capturar código potencialmente sujeito a erros:

 tente { console.log (p)
} catch (erro) { console.log (`Error: $ {error}`)//ReferenceError: p não está definido
}

Qualquer erro detectado no bloco try é lançado como uma exceção e capturado no bloco catch , mantendo nossos aplicativos mais resistentes a erros. No React, essa construção funciona bem para lidar com erros de JavaScript conforme abaixo, em que buscamos dados com useEffect :

 useEffect (()=> { tentar { fetchUsers (); } catch (erro) { setError (erro); }
}, []);

Mas isso não funciona tão bem em componentes React.

Por que try... catch não detecta erros de JavaScript em componentes React

É errado pensar que, em virtude do que faz e de como funciona, a instrução try... catch pode ser usada para detectar erros de JavaScript em componentes React. Isso ocorre porque a instrução try... catch funciona apenas para código imperativo, ao contrário de código declarativo que temos nos componentes.

 function ErrorFallbackUI ({errorMessage}) { Retorna ( 

Ocorreu um problema ao exibir o artigo:

{errorMessage}

); } //Há uma tentativa de colocar cada título de publicação em maiúsculas publicação função ({publicação}) { Retorna (

{publication.title.toUpperCase ()}

{publication.lead}

); } //Mapeie a lista de publicações e tente renderizar uma Publicações de função ({publicações}) { tentar { retornar publicações.map ((publicação, índice)=> (
)); } catch (erro) { return ; } }
Try Catch JavaScript Mensagem de erro de falha
Esta IU de fallback de erro foi cortada para mostrar a parte relevante. Ignore a IU de erro para ver o estado normal do aplicativo.

É importante observar que os erros acima só aparecerão durante o desenvolvimento. Na produção, a IU será corrompida e o usuário verá uma tela em branco. Como podemos resolver isso? Insira os limites do erro.

N.B. , ferramentas como create-react-app e Next.js têm um componente de sobreposição de erro que bloqueia a IU sempre que ocorre um erro, ofuscando seus próprios limites de erro. No create-react-app, que este tutorial usa, precisamos descartar ou fechar a sobreposição com a marca X no canto superior direito para visualizar nossos próprios limites de erro em uso.

Usando limites de erro no React

Limites de erro são componentes React que oferecem uma maneira de lidar com erros de JavaScript em componentes React. Com eles, podemos detectar erros de tempo de execução de JavaScript em nossos componentes, agir sobre esses erros e exibir uma IU substituta.

 importar ErrorBoundary de"error-boundary"; function Users () { Retorna ( 
{/* o resto do seu aplicativo */}
) }

Limites de erro operam como o bloco catch na instrução JavaScript try... catch com algumas exceções: eles são declarativos e, talvez nem seja necessário dizer, apenas catch erros nos componentes do React.

Mais especificamente, eles detectam erros em seu (s) componente (s) filho (s), durante a fase de renderização e nos métodos de ciclo de vida. Os erros lançados em qualquer um dos componentes filhos de um limite de erro serão delegados ao limite de erro mais próximo na árvore de componentes.

Em contraste, os limites de erro não detectam erros para, ou que ocorrem em:

Existem algumas regras a seguir para que um componente atue como um limite de erro:

  1. Deve ser um componente da aula
  2. Deve definir um ou ambos os métodos de ciclo de vida static getDerivedStateFromError () ou componentDidCatch ()

A regra é que static getDerivedStateFromError () deve ser usado para renderizar uma IU substituta após um erro ter sido lançado, enquanto componentDidCatch () deve ser usado para registre esses erros.

O componente abaixo é um limite de erro, pois satisfaz os critérios necessários:

 class PublicationErrorBoundary extends Component { estado={erro: falso, mensagem de erro:''}; static getDerivedStateFromError (error) { //Atualizar o estado para renderizar a IU substituta return {error: true, errorMessage: error.toString ()}; } componentDidCatch (error, errorInfo) { //Registrar o erro em um serviço de relatório de erros como o Sentry console.log ({erro, erroInfo}); } render () { const {erro, errorMessage}=this.state; const {crianças}=this.props; erro de retorno? : filhos; }
}

O substitui o bloco try... catch do componente acima com a seguinte atualização:

Publicações de

 função ({publicações}) { retornar publicações.map ((publicação, índice)=> ( 
)); }

Agora, o erro gerado por ao tentar maiúsculas cada título de publicação permite tratamento de exceção elegante . O erro foi isolado e uma IU substituta exibida.

Publication Typeerror Graceful Exception Handling Fallback UI
IU do aplicativo com limite de erro e uma IU substituta.

Você pode ver este exemplo em CodeSandbox .

Onde colocar limites de erro na árvore de componentes

A documentação do Next.js faz um bom trabalho ao explicar a regra geral : os limites do erro não devem ser muito granulares; eles são usados ​​pelo React na produção e devem sempre ser projetados intencionalmente.

Limites de erro são componentes React especiais e devem ser usados ​​para detectar erros apenas quando apropriado. Diferentes limites de erro podem ser usados ​​em diferentes partes de um aplicativo para lidar com erros contextuais, embora possam ser genéricos-por exemplo, um limite de erro de conexão de rede.

Observe que no exemplo anterior, é usado em Publicações em vez de Publicação . Se usado de outra forma, o erro gerado pela tentativa de colocar cada título de publicação em maiúsculas não será detectado pelo porque os filhos de serão um hiperlink e não um componente. No entanto, usá-lo em resolve isso.

//Isso não funcionará porque os filhos de `PublicationErrorBoundary`
//não são componentes
publicação função ({publicação}) { Retorna (   

{publication.title.toUpperCase ()}

{publication.lead}

); }

Além disso, observe que cada publicação tem um limite de erro que escuta seu erro. E se fizer sentido não exibir nenhuma publicação se houver um erro com pelo menos uma delas? pode ser atualizado:

//Antes
Publicações de função ({publicações}) { retornar publicações.map ((publicação, índice)=> ( 
)); } //Depois de. Observe a localização de `PublicationErrorBoundary` Publicações de função ({publicações}) { Retorna ( {publicações.map ((publicação, índice)=> (
))}
); }

A IU será atualizada para mostrar a IU substituta:

Erro Boundary Fallback UI Atualizado Notice

Erro de propagação de limite

Da mesma forma como o bloco catch funciona, se um limite de erro falhar ao tentar renderizar a mensagem de erro, o erro se propagará para o limite de erro mais próximo acima dele. Se os erros lançados não forem detectados por nenhum dos limites de erro, toda a árvore de componentes será desmontada.

Este é um novo comportamento a partir do React 16 , com o argumento é que é melhor remover completamente uma IU corrompida do que deixá-la no lugar e que isso fornece uma melhor experiência do usuário em caso de erro.

          

Pegue a árvore de componentes planejada acima como exemplo. Se um erro for detectado em , o limite de erro mais próximo, , será responsável por isso. Caso falhe em sua responsabilidade, atuará como reserva. Se isso também falhar, tentará lidar com o erro antes que o componente seja completamente desmontado.

Redefinindo limites de erro

Este é um dos casos extremos que encontro no uso de limites de erro. Normalmente, isso é feito redefinindo o estado da IU e recuperando a IU da corrupção.

Digamos que um usuário perca a conexão e um limite de erro de conexão tenha conseguido exibir uma IU substituta alertando o usuário para verificar sua conexão. Podemos recuperar a IU quando o estado da conexão se tornar ativo? A resposta simples é sim e a outra é que depende.

Os erros podem ser complicados, dinâmicos e não determinísticos, e é melhor você olhar para ferramentas de busca de dados como SWR ou React Query, ou pacote react-error-boundary , que alivia esses tipos de problemas.

Conclusão

Sempre que for racional fazer isso, você deve usar limites de erro para lidar com erros de tempo de execução em seus aplicativos React. Quanto mais familiarizado você fica com eles, mais entende a razão de sua existência.

Com o pacote react-error-boundary especificamente, você pode reduzir a quantidade de código redundante e incerteza que você encontra com uma abstração bem testada-que, como diz Kent Dodds , é o último componente de limite de erro de que alguém precisa.

A postagem Manipulando erros de JavaScript no React com limites de erro apareceu primeiro no LogRocket Blog .

Source link