Warum wird diese Komponente nach dem Auslösen eines Fehlers gerendert?

8

Ich verfolge derzeit die React JS-Dokumentation und bin auf ein Problem gestoßen, bei dem die Fehlergrenzen nicht wie erwartet funktionieren. Ich habe versucht, das in dem von den Dokumenten bereitgestellten CodePen gezeigte Beispiel und einige andere einfache Beispiele, die ich im Internet gefunden habe, zu replizieren, aber es funktioniert bei mir nicht genauso wie in der Demo, und ich habe Probleme zu verstehen warum.

Das genaue Problem ist, dass der Fehler zweimal ausgelöst wird, da die BuggyCounter-Komponente eine zusätzliche Zeit gerendert wird. Ich verstehe nicht, warum die Komponente ein zweites Mal gerendert wird.

Bitte schauen Sie sich dieses minimale Beispiel an.

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;

Die BuggyCounter-Komponente wird durch das <p>Tag ersetzt, das "Fehler" (was der gewünschte Effekt ist) darstellt, jedoch nur für einen Moment. Unmittelbar danach wird die Standardfehlerseite angezeigt, wodurch der Zweck der Fehlergrenzen aufgehoben wird.

Hier ist meine Konsole:

meine Fehler und Debug-Meldungen

Ich würde mich über Informationen zu diesem Thema freuen.

Vorübergehende Auflösung:

Es ist keine Antwort auf meine Frage, aber eine Möglichkeit, das redundante Rendern zu verhindern, besteht darin, den Fehler von componentDidUpdatestatt zu werfen 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
quelle
Gute Frage, ich habe keine Ahnung warum, aber wenn eine Komponente einen Fehler auslöst, wird sie möglicherweise selbst wiedergegeben? Keine Ahnung.
Vencovsky
2
Ich konnte den Fehler nicht in einer Sandbox replizieren. Codesandbox.io/s/react-example-slnhn
Prasanna
1
Ein seltsamer Punkt, den Sie hier betrachten sollten, ist, dass, wenn Sie vor dem Auslösen des Fehlers ein Protokoll hinzufügen und in dem componentDidCatchSie sehen, dass der Fehler zweimal ausgelöst wird, aber nur componenDidCatcheinmal übergeben wird.
Vencovsky
@Prasanna gleich hier
Vencovsky
Wenn jemand die Antwort von reagieren sehen möchte github.com/facebook/react/issues/17966
Vencovsky

Antworten:

3

Bearbeiten 2:

Nun, das Problem liegt in der Reaktionsversion 16.12.0. Wenn Sie es ändern, 16.0.0wird es nicht zweimal neu gerendert. Sie können dies in dieser Codesandbox testen, indem Sie die Reaktionsversion ändern.

Dies ist ein gutes Problem, das Sie bei React Github hinzufügen sollten.

Wahrscheinlich ist etwas intern in React Core Code. Abhängig von Ihrer Version wird es also zweimal oder nur einmal gerendert.


Bearbeiten:

Warum wird die Komponente erneut gerendert? Keine Ahnung.

Die Fehlerseite wird jedoch nur im Entwicklungsmodus angezeigt , sodass Sie componentDidCatcharbeiten.


Alte / schlechte Antwort

Die BuggyCounter-Komponente wird durch das <p>Tag ersetzt, das "Fehler" (was der gewünschte Effekt ist) darstellt, jedoch nur für einen Moment. Unmittelbar danach wird die Standardfehlerseite angezeigt, wodurch der Zweck der Fehlergrenzen aufgehoben wird.

Der only for a momentTeil ist nicht wahr. Die Fehlerseite ist eigentlich nur für die Entwicklung gedacht. Wenn Sie sie im Produktionsmodus ausführen, wird sie nicht angezeigt.

Und wie Sie in meinem Beispiel sehen können , wird beim Schließen der Fehlerseite die Fehlerkomponente angezeigt.

Dies wird in dieser Antwort erklärt .

In der von React Docs bereitgestellten Demoversion wird die Fehlerseite aufgrund der Konfiguration nicht angezeigt, nicht der Code selbst. Ihr Code funktioniert einwandfrei. Schließen Sie einfach die Fehlerseite und sehen Sie die Ergebnisse.

Vencovsky
quelle
Das BuggyCountermuss zweimal gerendert werden, wenn state.counter === 5im Protokoll zweimal "Rendering BuggyCounter. Count: 5" angezeigt wird. Ich glaube, Sie haben erklärt, warum ErrorHandlereine zusätzliche Zeit gerendert wird.
Anthony Yershov
Ich bin mir immer noch nicht sicher, warum BuggyCounternach dem Auslösen eines Fehlers ein zusätzliches Rendern durchgeführt wird.
Anthony Yershov
1
@AnthonyYershov das liegt daran, dass Sie Ihren Status in ändern componentDidCatch. Statusänderungen rendern Ihre Komponente erneut.
Prasanna
@ Prasanna ja genau. Deshalb wird ErrorHandleres wieder gerendert. Das ist nicht meine Frage. Wenn Sie sich das Protokoll ansehen, BuggyCounterwird es eine zusätzliche Zeit gerendert, bevor ErrorHandleres aufgrund einer Statusänderung erneut gerendert wird.
Anthony Yershov
1
Ich kann bestätigen, dass dieses Problem in React 16.0.0 nicht vorhanden ist. Vielen Dank für diese Informationen und dafür, dass Sie dieses Problem auf dem React Github angesprochen haben.
Anthony Yershov