ReactJS: errore di profondità massima di aggiornamento superato


177

Sto cercando di attivare / disattivare lo stato di un componente in ReactJS ma viene visualizzato un errore che indica:

Profondità di aggiornamento massima superata. Ciò può accadere quando un componente chiama ripetutamente setState all'interno di componentWillUpdate o componentDidUpdate. React limita il numero di aggiornamenti nidificati per evitare loop infiniti.

Non vedo il ciclo infinito nel mio codice, qualcuno può aiutare?

Codice componente ReactJS:

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;

35
Cambiare this.toggle()per this.toggleo{()=> this.toggle()}
studente

8
Un altro miglioramento, sebbene non correlato al problema: trasformalo toggle(){...}in toggle = () => {...}modo da non averne bisogno bind!
Berry M.

Grazie @learner. Mi hai aiutato anche tu. Spiegheresti gentilmente il motivo della tua soluzione. Qual è la differenza tra quei due?
Shamim,

2
@Shamim È la differenza tra chiamare una funzione esistente e passare il riferimento a una funzione. È utile capire che stiamo scrivendo il codice da visualizzare e attivare quando l'utente fa qualcosa, non il codice da attivare non appena l'utente carica la pagina. reactjs.org/docs/faq-functions.html
DisplayName

Risposte:


274

che poiché si chiama attiva / disattiva all'interno del metodo di rendering che provocherà nuovamente il rendering e l'attivazione / disattivazione chiamerà di nuovo e ridistribuirà di nuovo e così via

questa riga al tuo codice

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

devi fare onClickriferimento a this.togglenon chiamarlo

per risolvere il problema, procedere come segue

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

8
Sto affrontando una situazione simile, ma devo passare un parametro per attivare / disattivare, come può essere realizzato?
Niveditha Karmegam,

58
@NivedithaKarmegam Do onClick={(param) => this.toggle(param)}. Questo non si attiverà immediatamente (e non verrà eseguito il rendering). Questa è una definizione di callback (funzione freccia).
Fabian Picone,

15
@FabianPicone ha provato il tuo metodo ma quando i console.log mostra che "param" è stato passato come evento, in realtà dovrebbe farloonClick={() => this.toggle(param)}
iWillGetBetter

6
@iWillGetBetter Sì, il primo parametro in onClick è l'evento click. Se hai bisogno di un parametro aggiuntivo puoi passarlo anche onClick={(event) => this.toggle(event, myParam)}.
Fabian Picone,

1
Ho questa funzione closeEditModal = () => this.setState({openEditModal: false});Come chiamarla nel rendering?
Nux,

31

È necessario passare l'oggetto evento quando si chiama la funzione:

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

Se non hai bisogno di gestire l'evento onClick puoi anche digitare:

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

Ora puoi anche aggiungere i tuoi parametri all'interno della funzione.


2
L'oggetto evento viene inviato automaticamente se non viene specificato nulla. Includi solo un parametro di input nella funzione chiamata.
Jeff Pinkston,

2
{<td><span onClick={() => this.toggle(whateverParameter)}>Details</span></td>}fa il trucco per me
iWillGetBetter

22

Dimentica innanzitutto la reazione:
non è correlato alla reazione e cerchiamo di comprendere i concetti di base di Java Script. Ad esempio hai scritto la seguente funzione nello script java (il nome è A).

function a() {

};

Q.1) Come chiamare la funzione che abbiamo definito?
Ans: a ();

Q.2) Come passare il riferimento della funzione in modo da poterlo chiamare quest'ultimo?
Ans: let fun = a;

Ora arrivando alla tua domanda, hai usato la paresi con il nome della funzione, significa che la funzione verrà chiamata quando verrà visualizzata la seguente istruzione.

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

Quindi come correggerlo?
Semplice!! Rimuovi la parentesi. In questo modo hai fornito il riferimento di quella funzione all'evento onClick. Richiama la funzione solo quando si fa clic sul componente.

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

Un suggerimento ribadito per reagire:
evitare di utilizzare la funzione inline come suggerito da qualcuno nelle risposte, potrebbe causare problemi di prestazioni. Evita il seguente codice, creerà ripetutamente l'istanza della stessa funzione ogni volta che la funzione verrà chiamata (l'istruzione lamda crea ogni volta una nuova istanza).
Nota: e non è necessario passare esplicitamente l'evento (e) alla funzione. puoi accedervi con nella funzione senza passarlo.

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

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


6

So che questo ha molte risposte, ma dal momento che la maggior parte di loro sono vecchie (beh, più vecchie), nessuna menziona l'approccio con cui cresco molto velocemente. In breve:

Utilizzare componenti e ganci funzionali .

Più a lungo:

Cerca di utilizzare quanti più componenti funzionali invece di quelli di classe soprattutto per il rendering , E cerca di mantenerli il più puri possibile (sì, i dati sono sporchi per impostazione predefinita, lo so).

Due vantaggi chiaramente evidenti dei componenti funzionali (ce ne sono altri):

  • Purezza o quasi purezza rendono il debug molto più semplice
  • I componenti funzionali eliminano la necessità del codice della caldaia del costruttore

Prova rapida per il 2 ° punto - Non è assolutamente disgustoso?

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

Se stai usando componenti funzionali per più di un rendering, avrai bisogno della seconda parte di grandi duo - hook. Perché sono migliori dei metodi del ciclo di vita, cos'altro possono fare e molto altro mi richiederebbe molto spazio da coprire, quindi ti consiglio di ascoltare l'uomo stesso: Dan che predica i ganci

In questo caso sono necessari solo due ganci:

Un hook di callback comodamente chiamato useCallback. In questo modo si impedisce l'associazione ripetuta della funzione quando si esegue nuovamente il rendering.

Un hook di stato, chiamato useState, per mantenere lo stato nonostante l'intero componente sia funzionante ed eseguito nella sua interezza (sì, questo è possibile a causa della magia degli hook). All'interno di quel hook, memorizzerai il valore di toggle.

Se leggi questa parte, probabilmente vorrai vedere tutto ciò di cui ho parlato in azione e applicato al problema originale. Ecco qua: Demo

Per quelli di voi che vogliono solo dare un'occhiata al componente e WTF è questo, eccovi qui:

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: L'ho scritto nel caso in cui molte persone arrivassero qui con problemi simili. Spero che a loro piacerà quello che vedono almeno abbastanza bene da cercarlo un po 'di più. Non sono io che sto dicendo che le altre risposte sono sbagliate, sono io che sto dicendo che dal momento in cui sono state scritte, c'è un altro modo (IMHO, uno migliore) di occuparsene.


5

se non hai bisogno di passare argomenti per funzionare, rimuovi () dalla funzione come sotto:

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

ma se vuoi passare argomenti, dovresti fare come di seguito:

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

3

ReactJS: errore di profondità massima di aggiornamento superato

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

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

perché quel?

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

La funzione onDigit imposta lo stato, che provoca un rerender, che provoca l'attivazione di onDigit perché questo è il valore che stai impostando come onClick che provoca l'impostazione dello stato che provoca un rerender, che provoca l'attivazione di onDigit perché è il valore che ' re ... ecc


3

1.Se vogliamo passare l'argomento nella chiamata, allora dobbiamo chiamare il metodo come sotto Dato che stiamo usando le funzioni freccia non è necessario associare il metodo cunstructor.

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

quando associamo il metodo nel costruttore in questo modo

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

allora dobbiamo chiamare il metodo senza passare alcun argomento come di seguito

onClick={this.save}

e proviamo a passare l'argomento mentre chiamiamo la funzione come mostrato sotto, quindi l'errore arriva come superata la massima profondità.

 onClick={this.save(id)}

1

suClicca dovresti chiamare la funzione, questa è chiamata la tua funzione attiva / disattiva.

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


1

In questo caso, questo codice

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

fa sì che la funzione di attivazione / disattivazione venga chiamata immediatamente e venga ripetuta ripetutamente in modo da effettuare chiamate infinite.

quindi passare solo il riferimento a quel metodo di attivazione / risoluzione risolverà il problema.

così ,

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

sarà il codice della soluzione.

Se si desidera utilizzare il simbolo (), è necessario utilizzare una funzione freccia come questa

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

Nel caso in cui desideri passare parametri, dovresti scegliere l'ultima opzione e puoi passare parametri come questo

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

Nell'ultimo caso non chiama immediatamente e non provoca il rendering della funzione, evitando così chiamate infinite.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.