Por que esse componente está sendo renderizado após gerar um erro?


8

Atualmente, estou acompanhando a documentação do React JS e encontrei um problema com os limites de erro que não estavam funcionando conforme o esperado. Tentei replicar o exemplo mostrado no CodePen fornecido pelos documentos e alguns outros exemplos simples que encontrei na internet, no entanto, ele não está funcionando da mesma forma que na demonstração e estou com dificuldades. para entender o porquê.

O problema exato é que o erro está sendo gerado duas vezes porque o componente BuggyCounter é processado por um tempo extra. Eu não entendo por que o componente está renderizando uma segunda vez.

Por favor, dê uma olhada neste exemplo mínimo.

import React, { Component } from 'react';

function App() {
  return (
    <ErrorHandler>
      <BuggyCounter />
    </ErrorHandler>
  );
}

class ErrorHandler extends Component {
  constructor(props) {
    super(props);
    this.state = {
      error: false,
      errorInfo: null
    }
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ error, errorInfo });
  }

  render() {
    console.log('rendering ErrorHandler. ' + (this.state.error ? "error" : "no error"));
    if(this.state.error) {
      return <p>Error</p>
    }
    return this.props.children;
  }
}

class BuggyCounter extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
  }

  handleClick = () => {
    this.setState(({ counter }) => ({
      counter: counter + 1
    }));
  };

  render() {
    console.log('rendering BuggyCounter. count: ' + this.state.counter);
    if (this.state.counter === 5) {
      throw new Error('I crashed!');
    }
    return <h1 onClick={this.handleClick}>{this.state.counter}</h1>
  }
}

export default App;

O componente BuggyCounter está sendo substituído pela <p>tag que gera "Erro" (que é o efeito desejado), mas apenas por um momento. Imediatamente depois disso, a página de erro padrão está sendo mostrada, anulando a finalidade dos limites de erro.

Aqui está o meu console:

meus erros e mensagens de depuração

Agradecemos qualquer informação que você possa fornecer sobre este tópico.

Resolução temporária:

Não é uma resposta para minha pergunta, mas uma maneira de impedir a renderização redundante é lançar o erro em componentDidUpdatevez de render.

  render() {
    console.log('rendering BuggyCounter. count: ' + this.state.counter);
    return <h1 onClick={this.handleClick}>{this.state.counter}</h1>
  }

  componentDidUpdate() {
    if(this.state.counter === 5)
      throw new Error('I crashed');
  }

Boa pergunta, não tenho idéia do porquê, mas talvez quando um componente gera um erro, ele se renderize novamente? Nenhuma pista.
— Vencovsky

2
Não foi possível replicar o erro em uma sandbox codesandbox.io/s/react-example-slnhn
— Prasanna

1
Um ponto estranho a se observar aqui é que, se você adicionar um log antes de lançar o erro componentDidCatch, verá que ele lança o erro duas vezes, mas apenas passa componenDidCatchuma vez.
— Vencovsky

@Prasanna mesmo aqui
— Vencovsky

Se alguém quiser ver a resposta de react github.com/facebook/react/issues/17966
— Vencovsky em

Respostas:


3

Edição 2:

Bem, o problema está na versão react 16.12.0, se você mudar para 16.0.0, ele não será renderizado duas vezes mais. Você pode testar isso nesta caixa de código , alterando a versão de reação.

Esse é um bom problema para adicionar no react github.

Provavelmente é algo internamente no código principal do react. Portanto, dependendo da sua versão, ela será renderizada duas ou apenas uma vez.


Editar:

Por que o componente é renderizado novamente? Nenhuma idéia.

Mas, a página de erro é mostrada apenas no modo de desenvolvimento , portanto você componentDidCatchestá trabalhando.


Resposta antiga / ruim

O componente BuggyCounter está sendo substituído pela <p>tag que gera "Erro" (que é o efeito desejado), mas apenas por um momento. Imediatamente depois disso, a página de erro padrão está sendo mostrada, anulando a finalidade dos limites de erro.

A only for a momentparte não é verdadeira. A página de erro é apenas para desenvolvimento, se você a executar no modo de produção, ela não será mostrada.

E como você pode ver no meu exemplo , se você fechar a página de erro, verá o componente de erro.

Isso é explicado nesta resposta .

Portanto, na versão demo fornecida pelo react docs, ela não mostra a página de erro devido à sua configuração, e não ao código. Seu código está funcionando bem, basta fechar a página de erro e ver os resultados.


Ele BuggyCounterdeve estar sendo renderizado duas vezes quando, state.counter === 5porque o log mostra "Rendering BuggyCounter. Count: 5" duas vezes. Eu acredito que você explicou por que ErrorHandlerestá sendo processado um tempo extra.
— Anthony Yershov

Ainda não estou claro por que BuggyCounterestá executando uma renderização adicional após gerar um erro.
— Anthony Yershov

1
@AnthonyYershov é porque você está mudando de estado componentDidCatch. Alterações de estado renderizarão novamente seu componente.
— Prasanna

@ Pasanna sim exatamente. É por isso que ErrorHandlerestá sendo renderizado novamente. Essa não é a minha pergunta. Se você olhar para o log, BuggyCounterestá sendo renderizado um tempo extra antes de ErrorHandlerser renderizado novamente devido a alterações de estado.
— Anthony Yershov

1
Posso confirmar que esse problema não existe no React 16.0.0, obrigado por essas informações e por ter levantado esse problema no github do react.
— Anthony Yershov
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.