ReactJS: Die maximale Aktualisierungstiefe hat den Fehler überschritten

175

Ich versuche, den Status einer Komponente in ReactJS umzuschalten, erhalte jedoch die folgende Fehlermeldung:

Maximale Aktualisierungstiefe überschritten. Dies kann passieren, wenn eine Komponente setState wiederholt in componentWillUpdate oder componentDidUpdate aufruft. React begrenzt die Anzahl verschachtelter Updates, um Endlosschleifen zu vermeiden.

Ich sehe die Endlosschleife in meinem Code nicht. Kann mir jemand helfen?

ReactJS-Komponentencode:

import React, { Component } from 'react';
import styled from 'styled-components';

class Item extends React.Component {
    constructor(props) {
        super(props);     
        this.toggle= this.toggle.bind(this);
        this.state = {
            details: false
        } 
    }  
    toggle(){
        const currentState = this.state.details;
        this.setState({ details: !currentState }); 
    }

    render() {
        return (
            <tr className="Item"> 
                <td>{this.props.config.server}</td>      
                <td>{this.props.config.verbose}</td> 
                <td>{this.props.config.type}</td>
                <td className={this.state.details ? "visible" : "hidden"}>PLACEHOLDER MORE INFO</td>
                {<td><span onClick={this.toggle()}>Details</span></td>}
            </tr>
    )}
}

export default Item;
Maja Okholm
quelle
35
Wechseln Sie this.toggle()zu this.toggleoder{()=> this.toggle()}
Lernender
8
Eine weitere Verbesserung, die jedoch nichts mit Ihrem Problem toggle(){...}zu toggle = () => {...}tun hat : Machen Sie es so, dass Sie es nicht brauchen bind!
Berry M.
Danke @Learner. Du hast mir auch geholfen. Würden Sie bitte den Grund für Ihre Lösung erläutern? Was ist der Unterschied zwischen diesen beiden?
Shamim
2
@Shamim Es ist der Unterschied zwischen dem Aufrufen einer vorhandenen Funktion und dem Übergeben des Verweises an eine Funktion. Es ist hilfreich zu verstehen, dass wir Code schreiben, der angezeigt und ausgelöst wird, wenn der Benutzer etwas tut, und keinen Code, der ausgelöst wird, sobald der Benutzer die Seite lädt. reactjs.org/docs/faq-functions.html
Anzeigename

Antworten:

271

Dies liegt daran, dass Sie toggle innerhalb der Render-Methode aufrufen, wodurch erneut gerendert und umgeschaltet wird. Dies wird erneut aufgerufen und erneut gerendert und so weiter

diese Zeile bei Ihrem Code

{<td><span onClick={this.toggle()}>Details</span></td>}

Sie müssen darauf onClickverweisen, this.toggledass Sie es nicht aufrufen

Um das Problem zu beheben , tun Sie dies

{<td><span onClick={this.toggle}>Details</span></td>}
Ali
quelle
8
Ich bin mit einer ähnlichen Situation konfrontiert, muss jedoch einen Parameter übergeben, um umzuschalten. Wie kann dies erreicht werden?
Niveditha Karmegam
58
@NivedithaKarmegam Do onClick={(param) => this.toggle(param)}. Dies wird nicht sofort ausgelöst (und erneut gerendert). Dies ist eine Rückrufdefinition (Pfeilfunktion).
Fabian Picone
15
@FabianPicone versuchte Ihre Methode, aber wenn ich console.log, zeigt es, dass "param" als Ereignis übergeben wurde, sollte eigentlich tunonClick={() => this.toggle(param)}
iWillGetBetter
6
@iWillGetBetter Ja, der erste Parameter in onClick ist das Klickereignis. Wenn Sie einen zusätzlichen Parameter benötigen, können Sie diesen auch übergeben onClick={(event) => this.toggle(event, myParam)}.
Fabian Picone
1
Ich habe diese Funktion closeEditModal = () => this.setState({openEditModal: false});Wie rufe ich es beim Rendern auf?
Nux
31

Sie sollten das Ereignisobjekt übergeben, wenn Sie die Funktion aufrufen:

{<td><span onClick={(e) => this.toggle(e)}>Details</span></td>}

Wenn Sie das onClick-Ereignis nicht verarbeiten müssen, können Sie auch Folgendes eingeben:

{<td><span onClick={(e) => this.toggle()}>Details</span></td>}

Jetzt können Sie auch Ihre Parameter innerhalb der Funktion hinzufügen.

Florent Philippe
quelle
2
Das Ereignisobjekt wird automatisch gesendet, wenn nichts angegeben ist. Fügen Sie einfach einen Eingabeparameter in die aufgerufene Funktion ein.
Jeff Pinkston
2
{<td><span onClick={() => this.toggle(whateverParameter)}>Details</span></td>}macht den Trick für mich
iWillGetBetter
22

Vergessen Sie zuerst die Reaktion:
Dies hängt nicht mit der Reaktion zusammen und lassen Sie uns die grundlegenden Konzepte von Java Script verstehen. Zum Beispiel haben Sie folgende Funktion in Java-Skript geschrieben (Name ist A).

function a() {

};

Q.1) Wie rufe ich die von uns definierte Funktion auf?
Ans: a ();

Q.2) Wie übergebe ich eine Funktionsreferenz, damit wir sie letztere nennen können?
Ans: lass Spaß = a;

Wenn Sie nun zu Ihrer Frage kommen, haben Sie eine Klammer mit dem Funktionsnamen verwendet. Dies bedeutet, dass die Funktion aufgerufen wird, wenn die folgende Anweisung gerendert wird.

<td><span onClick={this.toggle()}>Details</span></td>

Wie kann man es dann korrigieren?
Einfach!! Entfernen Sie einfach die Klammern. Auf diese Weise haben Sie den Verweis dieser Funktion auf das Ereignis onClick gegeben. Ihre Funktion wird nur zurückgerufen, wenn auf Ihre Komponente geklickt wird.

 <td><span onClick={this.toggle}>Details</span></td>

Ein Vorschlag zur Reaktion:
Vermeiden Sie die Verwendung der Inline-Funktion, wie sie von jemandem in den Antworten vorgeschlagen wurde. Dies kann zu Leistungsproblemen führen. Vermeiden Sie den folgenden Code. Bei jedem Aufruf der Funktion wird immer wieder eine Instanz derselben Funktion erstellt (die lamda-Anweisung erstellt jedes Mal eine neue Instanz).
Hinweis: und es ist nicht erforderlich, Ereignis (e) explizit an die Funktion zu übergeben. Sie können mit in der Funktion darauf zugreifen, ohne es zu übergeben.

{<td><span onClick={(e) => this.toggle(e)}>Details</span></td>}

https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578

Piyush N.
quelle
6

Ich weiß, dass dies viele Antworten hat, aber da die meisten von ihnen alt sind (na ja, älter), erwähnt keiner den Ansatz, für den ich sehr schnell gewachsen bin. Zusamenfassend:

Verwenden Sie Funktionskomponenten und Haken .

Länger:

Versuchen Sie, so viele Funktionskomponenten anstelle von Klassenkomponenten zu verwenden, insbesondere für das Rendern , UND versuchen Sie, sie so rein wie möglich zu halten (ja, Daten sind standardmäßig verschmutzt, wie ich weiß).

Zwei offensichtliche Vorteile von Funktionskomponenten (es gibt noch mehr):

  • Reinheit oder nahezu Reinheit machen das Debuggen so viel einfacher
  • Funktionskomponenten machen Konstruktorkesselcode überflüssig

Schneller Beweis für den 2. Punkt - Ist das nicht absolut widerlich?

constructor(props) {
        super(props);     
        this.toggle= this.toggle.bind(this);
        this.state = {
            details: false
        } 
    }  

Wenn Sie Funktionskomponenten für mehr als das Rendern verwenden, benötigen Sie den zweiten Teil großartiger Duo-Hooks. Warum sind sie besser als Lebenszyklusmethoden, was können sie sonst noch tun und vieles mehr würde mir viel Platz in Anspruch nehmen. Ich empfehle Ihnen, dem Mann selbst zuzuhören: Dan predigt die Haken

In diesem Fall benötigen Sie nur zwei Haken:

Ein Callback-Hook mit dem bequemen Namen useCallback. Auf diese Weise verhindern Sie, dass die Funktion beim erneuten Rendern immer wieder gebunden wird.

Ein Status-Hook, der aufgerufen wird useState, um den Status beizubehalten, obwohl die gesamte Komponente funktioniert und vollständig ausgeführt wird (ja, dies ist aufgrund der Magie von Hooks möglich). In diesem Hook speichern Sie den Wert von Toggle.

Wenn Sie diesen Teil lesen, möchten Sie wahrscheinlich alles, worüber ich gesprochen habe, in Aktion sehen und auf das ursprüngliche Problem anwenden. Los geht's: Demo

Für diejenigen unter Ihnen, die nur einen Blick auf die Komponente werfen möchten und WTF das ist, hier sind Sie:

const Item = () => {

    // HOOKZ
  const [isVisible, setIsVisible] = React.useState('hidden');

  const toggle = React.useCallback(() => {
    setIsVisible(isVisible === 'visible' ? 'hidden': 'visible');
  }, [isVisible, setIsVisible]);

    // RENDER
  return (
  <React.Fragment>
    <div style={{visibility: isVisible}}>
        PLACEHOLDER MORE INFO
    </div>
    <button onClick={toggle}>Details</button>
  </React.Fragment>
  )
};

PS: Ich habe das geschrieben, falls viele Leute mit ähnlichen Problemen hier landen. Hoffentlich wird ihnen das, was sie sehen, zumindest gut genug gefallen, um es ein bisschen mehr zu googeln. Ich sage nicht, dass andere Antworten falsch sind, ich sage, dass es seit dem Zeitpunkt, an dem sie geschrieben wurden, einen anderen Weg gibt (IMHO, einen besseren), damit umzugehen.

DanteTheSmith
quelle
5

Wenn Sie keine Argumente an function übergeben müssen, entfernen Sie einfach () aus der Funktion wie folgt:

<td><span onClick={this.toggle}>Details</span></td>

Wenn Sie jedoch Argumente übergeben möchten, sollten Sie Folgendes tun:

<td><span onClick={(e) => this.toggle(e,arg1,arg2)}>Details</span></td>
Abolfazl Miadian
quelle
3

ReactJS: Die maximale Aktualisierungstiefe hat den Fehler überschritten

inputDigit(digit){
  this.setState({
    displayValue: String(digit)
  })

<button type="button"onClick={this.inputDigit(0)}>

Warum das?

<button type="button"onClick={() => this.inputDigit(1)}>1</button>

Die Funktion onDigit legt den Status fest, der ein erneutes Rendern verursacht, wodurch onDigit ausgelöst wird, da dies der Wert ist, den Sie als onClick festlegen. Dadurch wird der Status festgelegt, der ein erneutes Rendern verursacht. Dadurch wird onDigit ausgelöst, da dies der von Ihnen angegebene Wert ist. re… Etc

Rizo
quelle
3

1.Wenn wir im Aufruf ein Argument übergeben möchten, müssen wir die Methode wie folgt aufrufen. Da wir Pfeilfunktionen verwenden, müssen wir die Methode nicht einbinden cunstructor.

onClick={() => this.save(id)} 

wenn wir die Methode im Konstruktor so binden

this.save= this.save.bind(this);

dann müssen wir die Methode aufrufen, ohne ein Argument wie unten zu übergeben

onClick={this.save}

und wir versuchen, ein Argument zu übergeben, während wir die Funktion wie unten gezeigt aufrufen. Dann tritt ein Fehler auf, wenn die maximale Tiefe überschritten wird.

 onClick={this.save(id)}
Erstaunliche Apps
quelle
1

onClick sollten Sie function aufrufen, das heißt your function toggle.

onClick={() => this.toggle()}

Makkagru
quelle
1

In diesem Fall dieser Code

{<td><span onClick={this.toggle()}>Details</span></td>}

bewirkt, dass die Umschaltfunktion sofort aufgerufen und immer wieder neu gerendert wird, wodurch unendlich viele Aufrufe getätigt werden.

Wenn Sie also nur den Verweis auf diese Umschaltmethode übergeben, wird das Problem gelöst.

so ,

{<td><span onClick={this.toggle}>Details</span></td>}

wird der Lösungscode sein.

Wenn Sie () verwenden möchten, sollten Sie eine Pfeilfunktion wie diese verwenden

{<td><span onClick={()=> this.toggle()}>Details</span></td>}

Wenn Sie Parameter übergeben möchten, sollten Sie die letzte Option auswählen und Sie können Parameter wie diese übergeben

{<td><span onClick={(arg)=>this.toggle(arg)}>Details</span></td>}

Im letzten Fall wird nicht sofort aufgerufen und die Funktion wird nicht neu gerendert, wodurch unendliche Aufrufe vermieden werden.

Badri Paudel
quelle