webentwicklung-frage-antwort-db.com.de

ReactJS - Wird das Rendering bei jedem Aufruf von "setState" aufgerufen?

Werden alle Komponenten und Unterkomponenten bei jedem Aufruf von setState erneut angezeigt?

Wenn ja warum? Ich dachte, die Idee war, dass React nur so wenig wie nötig lieferte - als sich der Zustand änderte. 

Im folgenden einfachen Beispiel werden beide Klassen erneut gerendert, wenn auf den Text geklickt wird, obwohl sich der Status bei nachfolgenden Klicks nicht ändert, da der Handler onClick die Variable state immer auf denselben Wert setzt:

this.setState({'test':'me'});

Ich hätte erwartet, dass Rendern nur dann stattfinden würden, wenn sich state-Daten geändert hätten.

Hier ist der Code des Beispiels als JS Fiddle und eingebettetes Snippet:

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>

[1]: http://jsfiddle.net/fp2tncmb/2/
361
Brad Parks

Werden alle Komponenten und Unterkomponenten bei jedem Aufruf von setState erneut angezeigt?

Standardmäßig - Ja.

Es gibt eine Methode boolean shouldComponentUpdate (object nextProps, object nextState). Jede Komponente verfügt über diese Methode, und es ist dafür verantwortlich zu bestimmen, "ob die Komponente aktualisiert werden soll (run render function)?" Jedes Mal, wenn Sie Status ändern oder neue Requisionen von der übergeordneten Komponente übergeben.

Sie können Ihre eigene Implementierung der Methode shouldComponentUpdate für Ihre Komponente schreiben, die Standardimplementierung gibt jedoch immer true zurück, dh die Renderfunktion wird immer neu ausgeführt.

Zitat aus offiziellen Dokumenten http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

In der Standardeinstellung sollte shouldComponentUpdate immer true zurückgeben, um .__ zu verhindern. subtile Fehler, wenn der Zustand an Ort und Stelle mutiert ist, aber wenn Sie auf .__ achten. Zustand immer als unveränderlich behandeln und nur aus Requisiten und Zustand lesen In render () können Sie shouldComponentUpdate mit einer .__ überschreiben. Implementierung, die die alten Requisiten und den Zustand mit ihren Ersatz.

Nächster Teil Ihrer Frage:

Wenn ja warum? Ich dachte, die Idee war, dass React nur so wenig wie nötig lieferte - als sich der Zustand änderte. 

Es gibt zwei Schritte, die wir "Rendern" nennen können:

  1. Virtuelles DOM-Rendering: Wenn die Methode render aufgerufen wird, wird eine neue virtuelle dom -Struktur der Komponente zurückgegeben. Wie bereits erwähnt, wird diese render-Methode immer aufgerufen, wenn Sie setState ()} aufrufen, da shouldComponentUpdate standardmäßig immer true zurückgibt. Daher gibt es hier in React standardmäßig keine Optimierung.

  2. Natives DOM-Rendern: React ändert reale DOM-Knoten in Ihrem Browser nur, wenn sie im virtuellen DOM geändert wurden und so wenig wie erforderlich - dies ist die großartige Funktion von React, die die echte DOM-Mutation optimiert und React schnell macht.

431
Petr

Nein, React rendert nicht alles, wenn sich der Status ändert.

  • Immer wenn eine Komponente schmutzig ist (ihr Status wurde geändert), werden diese Komponente und ihre Kinder erneut gerendert. Bis zu einem gewissen Grad wird so wenig wie möglich wiedergegeben. Das einzige Mal, wenn Rendering nicht aufgerufen wird, ist, wenn ein Zweig zu einem anderen Stamm verschoben wird, wo theoretisch nichts neu gerendert werden muss. In Ihrem Beispiel ist TimeInChild eine untergeordnete Komponente von Main. Sie wird also auch wiedergegeben, wenn sich der Zustand von Main ändert.

  • React vergleicht keine Statusdaten. Wenn setState aufgerufen wird, wird die Komponente als fehlerhaft markiert (was bedeutet, dass sie erneut gerendert werden muss). Beachten Sie jedoch, dass das reale DOM nur dann aufgerufen wird, wenn die render-Methode der Komponente aufgerufen wird, wenn sich die Ausgabe vom aktuellen DOM-Baum unterscheidet (a.k.a unterscheidet sich zwischen dem virtuellen DOM-Baum und dem Dokument-DOM-Baum). Auch wenn sich die state-Daten in Ihrem Beispiel nicht geändert haben, hat sich der Zeitpunkt der letzten Änderung geändert, wodurch sich das virtuelle DOM von dem DOM des Dokuments unterscheidet, weshalb der HTML-Code aktualisiert wird.

84
tungd

Ja. Sie ruft die render () - Methode jedes Mal auf, wenn wir stattdessen setState aufrufen, wenn "shouldComponentUpdate" false zurückgibt. 

3

Obwohl es in vielen anderen Antworten hier angegeben ist, sollte die Komponente entweder:

  • implementieren Sie shouldComponentUpdate, um nur zu rendern, wenn sich Status oder Eigenschaften ändern

  • wechseln Sie zur Erweiterung a PureComponent , die intern bereits eine shouldComponentUpdate-Methode für flache Vergleiche implementiert.

Hier ist ein Beispiel, das shouldComponentUpdate verwendet, das nur für diesen einfachen Anwendungsfall und Demonstrationszwecke funktioniert. Wenn dies verwendet wird, rendert sich die Komponente bei jedem Klick nicht mehr neu und wird bei der ersten Anzeige und nach einmaligem Klicken wiedergegeben.

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    shouldComponentUpdate: function(nextProps, nextState) {
      if (this.state == null)
        return true;
  
      if (this.state.test == nextState.test)
        return false;
        
      return true;
  },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>

0
Brad Parks