¿Por qué se procesa este componente después de arrojar un error?

8

Actualmente estoy siguiendo junto con la documentación de React JS y he encontrado un problema con los límites de error que no funcionan como se esperaba. He intentado replicar el ejemplo que se muestra en el CodePen proporcionado por los documentos, y algunos otros ejemplos simples que he encontrado en Internet, sin embargo, no funciona igual para mí que en la demostración y estoy luchando para entender por qué.

El problema exacto es que el error se produce dos veces porque el componente BuggyCounter se procesa un tiempo adicional. No entiendo por qué el componente está desgarrando por segunda vez.

Por favor, eche un vistazo a este ejemplo 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;

El componente BuggyCounter se está reemplazando con la <p>etiqueta que muestra "Error" (que es el efecto deseado), pero solo por un momento. Inmediatamente después de eso, se muestra la página de error predeterminada, lo que anula el propósito de los límites de error.

Aquí está mi consola:

mis errores y mensajes de depuración

Agradecería cualquier información que pudiera proporcionar sobre este tema.

Resolución temporal:

No es una respuesta a mi pregunta, pero una forma de evitar el renderizado redundante es arrojar el error en componentDidUpdatelugar de hacerlo 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');
  }
Anthony Yershov
fuente
Buena pregunta, no tengo idea de por qué, pero tal vez cuando un componente arroja un error, ¿vuelve a aparecer por sí mismo? Ninguna pista.
Vencovsky
2
No pude replicar el error en un sandbox codesandbox.io/s/react-example-slnhn
Prasanna
1
Un punto extraño a tener en cuenta aquí es que si agrega un registro antes de arrojar el error y componentDidCatchverá que arroja el error dos veces, pero solo pasa componenDidCatchuna vez.
Vencovsky
@Prasanna igual aquí
Vencovsky
Si alguien quiere ver la respuesta de react github.com/facebook/react/issues/17966
Vencovsky

Respuestas:

3

Edición 2:

Bueno, el problema está en la versión de reacción 16.12.0, si lo cambia a 16.0.0, no volverá a aparecer dos veces. Puede probar esto en esta caja de códigos cambiando la versión de reacción.

Este es un buen tema para agregar en react github.

Probablemente es algo interno en el código del núcleo de reacción. Entonces, dependiendo de su versión, se renderizará dos veces o solo una vez.


Editar:

¿Por qué el componente se retrae? Ni idea.

Pero, la página de error solo se muestra en modo de desarrollo , por lo que componentDidCatchestá funcionando.


Respuesta anterior / mala

El componente BuggyCounter se está reemplazando con la <p>etiqueta que muestra "Error" (que es el efecto deseado), pero solo por un momento. Inmediatamente después de eso, se muestra la página de error predeterminada, lo que anula el propósito de los límites de error.

La only for a momentparte no es verdad. La página de error es en realidad solo para desarrollo, si la ejecuta en modo de producción, no se mostrará.

Y como puede ver en mi ejemplo , si cierra la página de error, verá el componente de error.

Esto se explica en esta respuesta .

Entonces, en la versión de demostración proporcionada por react docs, no muestra la página de error debido a su configuración, no al código en sí. Su código funciona bien, solo cierre la página de error y vea los resultados.

Vencovsky
fuente
Se BuggyCounterdebe procesar dos veces cuando state.counter === 5el registro muestra "Rendering BuggyCounter. Count: 5" dos veces. Creo que ha explicado por qué ErrorHandlerse le presta un tiempo extra.
Anthony Yershov
Todavía no estoy claro por qué BuggyCounterestá realizando un renderizado adicional después de arrojar un error.
Anthony Yershov
1
@AnthonyYershov eso es porque estás cambiando tu estado componentDidCatch. Los cambios de estado le devolverán su componente.
Prasanna
@Prasanna sí exactamente. Es por eso que ErrorHandlerse vuelve a procesar. Esa no es mi pregunta. Si observa el registro, BuggyCounterse procesa un tiempo adicional antes de ErrorHandlervolver a representarse debido a un cambio de estado.
Anthony Yershov
1
Puedo confirmar que este problema no existe en React 16.0.0 gracias por esta información y por plantear este problema en el github react.
Anthony Yershov