ReactJS: erreur de dépassement de la profondeur de mise à jour maximale

179

J'essaie de basculer l'état d'un composant dans ReactJS mais j'obtiens une erreur indiquant:

Profondeur de mise à jour maximale dépassée. Cela peut se produire lorsqu'un composant appelle à plusieurs reprises setState dans componentWillUpdate ou componentDidUpdate. React limite le nombre de mises à jour imbriquées pour éviter des boucles infinies.

Je ne vois pas la boucle infinie dans mon code, quelqu'un peut-il m'aider?

Code composant 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;
Maja Okholm
la source
35
Changer this.toggle()pour this.toggleou{()=> this.toggle()}
apprenant
8
Une autre amélioration, bien que sans rapport avec votre problème: transformez-vous toggle(){...}en toggle = () => {...}pour que vous n'en ayez pas besoin bind!
Berry M.
Merci @learner. Vous m'avez aussi aidé. Pourriez-vous nous expliquer la raison de votre solution. Quelle est la différence entre ces deux?
Shamim
2
@Shamim C'est la différence entre appeler une fonction existante et passer la référence à une fonction. Il est utile de comprendre que nous écrivons du code à afficher et à déclencher lorsque l'utilisateur fait quelque chose, et non du code à déclencher dès que l'utilisateur charge la page. reactjs.org/docs/faq-functions.html
DisplayName

Réponses:

275

cela parce que vous appelez toggle à l'intérieur de la méthode de rendu qui entraînera le re-rendu et le basculement appellera à nouveau et re-restituera à nouveau et ainsi de suite

cette ligne à votre code

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

vous devez faire onClickréférence à this.togglene pas l'appeler

pour résoudre le problème, procédez comme suit

{<td><span onClick={this.toggle}>Details</span></td>}
Ali
la source
9
Je suis confronté à une situation similaire, mais je dois passer un paramètre pour basculer, comment cela peut-il être accompli?
Niveditha Karmegam
58
@NivedithaKarmegam Do onClick={(param) => this.toggle(param)}. Cela ne se déclenchera pas immédiatement (et ne se rendra pas). Il s'agit d'une définition de rappel (fonction de flèche).
Fabian Picone
16
@FabianPicone a essayé votre méthode, mais lorsque je console.log, cela montre que "param" a été passé comme événement, devrait en fait le faireonClick={() => this.toggle(param)}
iWillGetBetter
6
@iWillGetBetter Oui, le premier paramètre dans onClick est l'événement de clic. Si vous avez besoin d'un paramètre supplémentaire, vous pouvez le transmettre également onClick={(event) => this.toggle(event, myParam)}.
Fabian Picone
1
J'ai cette fonction closeEditModal = () => this.setState({openEditModal: false});Comment l'appeler en rendu?
Nux
31

Vous devez passer l'objet événement lors de l'appel de la fonction:

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

Si vous n'avez pas besoin de gérer l'événement onClick, vous pouvez également taper:

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

Vous pouvez maintenant également ajouter vos paramètres dans la fonction.

Florent Philippe
la source
2
L'objet événement est automatiquement envoyé si rien n'est spécifié. Incluez simplement un paramètre d'entrée dans la fonction appelée.
Jeff Pinkston
2
{<td><span onClick={() => this.toggle(whateverParameter)}>Details</span></td>}fait l'affaire pour moi
iWillGetBetter
22

Oubliez d'abord la réaction:
ce n'est pas lié à la réaction et comprenons les concepts de base de Java Script. Par exemple, vous avez écrit la fonction suivante dans un script java (le nom est A).

function a() {

};

Q.1) Comment appeler la fonction que nous avons définie?
Ans: a ();

Q.2) Comment passer la référence de la fonction pour qu'on puisse l'appeler celle-ci?
Ans: laissez amusant = a;

En arrivant maintenant à votre question, vous avez utilisé la paranthèse avec le nom de la fonction, ce qui signifie que la fonction sera appelée lorsque l'instruction suivante sera rendue.

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

Alors comment le corriger?
Facile!! Supprimez simplement les parenthèses. De cette manière, vous avez donné la référence de cette fonction à l'événement onClick. Il rappellera votre fonction uniquement lorsque votre composant sera cliqué.

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

Une suggestion réitérée pour réagir:
évitez d'utiliser la fonction en ligne comme suggéré par quelqu'un dans les réponses, cela peut entraîner des problèmes de performances. Évitez de suivre le code, cela créera une instance de la même fonction encore et encore chaque fois que la fonction sera appelée (l'instruction lamda crée une nouvelle instance à chaque fois).
Remarque: et pas besoin de passer l'événement (e) explicitement à la fonction. vous pouvez y accéder avec dans la fonction sans le passer.

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

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

Piyush N
la source
6

Je sais que cela a beaucoup de réponses, mais comme la plupart d'entre elles sont anciennes (enfin, plus âgées), aucune ne mentionne l'approche pour laquelle je grandis très vite. En bref:

Utilisez des composants fonctionnels et des crochets .

En plus:

Essayez d'utiliser autant de composants fonctionnels que de composants de classe, en particulier pour le rendu , ET essayez de les garder aussi purs que possible (oui, les données sont sales par défaut, je sais).

Deux avantages tout à fait évidents des composants fonctionnels (il y en a plus):

  • La pureté ou la quasi-pureté rend le débogage beaucoup plus facile
  • Les composants fonctionnels suppriment le besoin d'un code de chaudière constructeur

Preuve rapide pour le 2ème point - N'est-ce pas absolument dégoûtant?

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

Si vous utilisez des composants fonctionnels pour plus de rendu, vous aurez besoin de la deuxième partie d'un grand duo - hooks. Pourquoi sont-elles meilleures que les méthodes du cycle de vie, que peuvent-elles faire d'autre et bien plus encore me prendraient beaucoup d'espace à couvrir, alors je vous recommande d'écouter l'homme lui-même: Dan prêchant les crochets

Dans ce cas, vous n'avez besoin que de deux crochets:

Un hook de rappel nommé useCallback. De cette façon, vous évitez de relier la fonction à plusieurs reprises lorsque vous effectuez un nouveau rendu.

Un hook d'état, appelé useState, pour conserver l'état alors que tout le composant est fonctionnel et s'exécute dans son intégralité (oui, cela est possible grâce à la magie des hooks). Dans ce hook, vous stockerez la valeur de toggle.

Si vous lisez cette partie, vous voudrez probablement voir tout ce dont j'ai parlé en action et appliqué au problème d'origine. Ici vous allez: Démo

Pour ceux d'entre vous qui ne veulent que jeter un coup d'œil sur le composant et WTF, vous êtes ici:

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: J'ai écrit ceci au cas où de nombreuses personnes atterriraient ici avec un problème similaire. Espérons qu'ils aimeront ce qu'ils voient au moins assez bien pour le rechercher un peu plus sur Google. Ce n'est pas moi qui dis que les autres réponses sont fausses, c'est moi qui dis que depuis le temps où elles ont été écrites, il y a une autre façon (à mon humble avis, une meilleure) de gérer cela.

DanteTheSmith
la source
5

si vous n'avez pas besoin de passer d'arguments à la fonction, supprimez simplement () de la fonction comme ci-dessous:

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

mais si vous voulez passer des arguments, vous devriez faire comme ci-dessous:

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

ReactJS: erreur de dépassement de la profondeur de mise à jour maximale

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

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

pourquoi ça?

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

La fonction onDigit définit l'état, ce qui provoque un rerender, ce qui provoque le déclenchement de onDigit car c'est la valeur que vous définissez comme onClick, ce qui provoque la définition de l'état, ce qui provoque un rerender, ce qui provoque le déclenchement de onDigit car c'est la valeur que vous ' re… Etc

Rizo
la source
3

1.Si nous voulons passer un argument dans l'appel, nous devons appeler la méthode comme ci-dessous Comme nous utilisons des fonctions fléchées, il n'est pas nécessaire de lier la méthode cunstructor.

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

quand nous lions la méthode dans le constructeur comme ceci

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

alors nous devons appeler la méthode sans passer d'argument comme ci-dessous

onClick={this.save}

et nous essayons de passer l'argument tout en appelant la fonction comme indiqué ci-dessous, l'erreur survient comme une profondeur maximale dépassée.

 onClick={this.save(id)}
Applications étonnantes
la source
1

onClick vous devez appeler la fonction, qui a appelé votre bascule de fonction.

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

makkagru
la source
1

Dans ce cas, ce code

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

provoque l'appel immédiat de la fonction bascule et la restitue encore et encore, faisant ainsi des appels infinis.

donc ne passer que la référence à cette méthode de bascule résoudra le problème.

alors ,

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

sera le code de la solution.

Si vous souhaitez utiliser le (), vous devez utiliser une fonction de flèche comme celle-ci

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

Si vous voulez passer des paramètres, vous devez choisir la dernière option et vous pouvez passer des paramètres comme celui-ci

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

Dans le dernier cas, il n'appelle pas immédiatement et ne provoque pas le rendu de la fonction, évitant ainsi les appels infinis.

Badri Paudel
la source