React - TypeError non capturé: impossible de lire la propriété 'setState' de undefined


316

Je reçois l'erreur suivante

TypeError non capturé: impossible de lire la propriété «setState» de non défini

même après liaison delta dans le constructeur.

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count : 1
        };

        this.delta.bind(this);
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
    }
}

4
dans ES6, vous pouvez utiliser la fonction flèche pour la déclaration de fonction pour résoudre ce problème.
Tal

^ cela devrait être la bonne réponse
Jordec

J'ai changé ma fonction de réponse en ES6, et hurrey, son fonctionnement.
Ashwani Garg

Réponses:


449

Cela est dû au fait de this.deltane pas y être lié this.

Afin de lier l'ensemble this.delta = this.delta.bind(this)dans le constructeur:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

    this.delta = this.delta.bind(this);
}

Actuellement, vous appelez bind. Mais bind renvoie une fonction liée. Vous devez définir la fonction sur sa valeur liée.


188
À quoi bon les classes ES6 si leurs méthodes n'ont pas de thisliaison lexicale appropriée , puis n'exposent même pas une syntaxe pour lier leur contexte directement sur leur définition!?
AgmLauncher

1
je comprends votre point mais si j'écris du code dans componentWillMount () alors comment vais-je lier
suresh pareek

1
@sureshpareek Une fois que vous liez votre fonction dans le constructeur, elle doit ensuite être liée lorsque vous l'appelez à partir de n'importe quel hook de cycle de vie.
Levi Fuller

4
Venant du monde Android / Java, je suis déconcerté
Tudor

3
@AgmLauncher l'utilisation des fonctions Lambda lie implicitement cela. Si vous définissez deltacomme delta = () => { return this.setState({ count: this.state.count++ }); };le code fonctionnerait également. Expliqué ici: hackernoon.com/…
K. Rhoda

145

Dans ES7 + (ES2016), vous pouvez utiliser l' opérateur de syntaxe de liaison de la fonction expérimentale ::pour effectuer la liaison. C'est un sucre syntaxique et fera la même chose que la réponse de Davin Tryon.

Vous pouvez ensuite réécrire this.delta = this.delta.bind(this);dansthis.delta = ::this.delta;


Pour ES6 + (ES2015), vous pouvez également utiliser la fonction de flèche ES6 + ( =>) pour pouvoir l'utiliser this.

delta = () => {
    this.setState({
        count : this.state.count + 1
    });
}

Pourquoi ? Du document Mozilla:

Jusqu'à ce que les fonctions de direction, chaque nouvelle fonction définie par son propre cette valeur [...]. Cela s'est avéré ennuyeux avec un style de programmation orienté objet.

Les fonctions fléchées capturent cette valeur du contexte englobant [...]


3
Bel article décrivant cela en détail: reactkungfu.com/2015/07/…
Edo

Quel est l'avantage d'utiliser l'un sur l'autre, outre la syntaxe?
Jeremy D

2
La syntaxe de liaison est plus propre car vous pouvez conserver la portée normale de votre méthode.
Fabien Sa

La syntaxe de liaison ne fait pas partie d'ES2016 ou ES2017.
Felix Kling

2
@stackoverflow devrait ajouter la possibilité d'ajouter une prime à n'importe quelle réponse.
Gabe

29

Il existe une différence de contexte entre les classes ES5 et ES6. Il y aura donc également une petite différence entre les implémentations.

Voici la version ES5:

var Counter = React.createClass({
    getInitialState: function() { return { count : 1 }; },
    delta: function() {
        this.setState({
            count : this.state.count++
        });
    },
    render: function() {
        return (
            <div>
              <h1>{this.state.count}</h1>
              <button onClick={this.delta}>+</button>
            </div>
            );
    }
});

et voici la version ES6:

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count : 1 };
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
              <h1>{this.state.count}</h1>
              <button onClick={this.delta.bind(this)}>+</button>
            </div>
            );
    }
}

Faites juste attention, à côté de la différence de syntaxe dans l'implémentation de classe, il y a une différence dans la liaison du gestionnaire d'événements.

Dans la version ES5, c'est

              <button onClick={this.delta}>+</button>

Dans la version ES6, c'est:

              <button onClick={this.delta.bind(this)}>+</button>

L'utilisation des fonctions fléchées ou de la liaison dans JSX est une mauvaise pratique. stackoverflow.com/questions/36677733/… .
Fabien Sa

24

Lorsque vous utilisez du code ES6 dans React, utilisez toujours les fonctions fléchées, car ce contexte est automatiquement lié à celui-ci

Utilisez ceci:

(videos) => {
    this.setState({ videos: videos });
    console.log(this.state.videos);
};

au lieu de:

function(videos) {
    this.setState({ videos: videos });
    console.log(this.state.videos);
};

2
Si vous utilisez la fonction flèche et la variable de paramètre est la même que la variable clé , je recommanderais de l'utiliser comme this.setState({videos});
jayeshkv

C'est ce qui m'a fait ça. Je suis nouveau sur node, et les documents du module axios étaient incompatibles avec react et setState
dabobert

20

Vous n'avez rien à lier, utilisez simplement les fonctions fléchées comme ceci:

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count: 1
        };

    }
    //ARROW FUNCTION
    delta = () => {
        this.setState({
            count: this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
    }
}

cela fonctionne quelle est la différence s'il vous plaît pourquoi est-ce?
Ridha Rezzag

4
La portée this avec les fonctions fléchées est héritée du contexte. Avec les fonctions régulières, cela fait toujours référence à la fonction la plus proche, tandis qu'avec les fonctions fléchées, ce problème est supprimé, et vous n'aurez plus jamais besoin d'écrire var that = this. @RezzagRidha
Gabo Ruiz

1
À partir de 2019, c'est la voie à suivre (Y)
MH

6

Vous pouvez aussi utiliser:

<button onClick={()=>this.delta()}>+</button>

Ou:

<button onClick={event=>this.delta(event)}>+</button>

Si vous passez quelques paramètres ..


C'est une mauvaise pratique d'utiliser les fonctions fléchées dans JSX
Gabe

5

Vous devez le lier au constructeur et n'oubliez pas que les modifications apportées au constructeur doivent redémarrer le serveur. Sinon, vous finirez avec la même erreur.


1
Tirait mes cheveux parce que je n'ai pas redémarré le serveur.
kurtcorbett

5

Vous devez lier vos méthodes avec 'this' (objet par défaut). Donc, quelle que soit votre fonction, il suffit de la lier dans le constructeur.

constructor(props) {
    super(props);
    this.state = { checked:false };

    this.handleChecked = this.handleChecked.bind(this);
}

handleChecked(){
    this.setState({
        checked: !(this.state.checked)
    })
}

render(){
    var msg;

    if(this.state.checked){
        msg = 'checked'
    }
    else{
        msg = 'not checked'
    }

    return (
        <div>               
            <input type='checkbox' defaultChecked = {this.state.checked} onChange = {this.handleChecked} />
            <h3>This is {msg}</h3>
        </div>
    );

4

Cette erreur peut être résolue par différentes méthodes -

  • Si vous utilisez la syntaxe ES5 , selon la documentation React js, vous devez utiliser la méthode bind .

    Quelque chose comme ça pour l'exemple ci-dessus:

    this.delta = this.delta.bind(this)

  • Si vous utilisez la syntaxe ES6 , vous n'avez pas besoin d'utiliser la méthode bind , vous pouvez le faire avec quelque chose comme ceci:

    delta=()=>{ this.setState({ count : this.state.count++ }); }


2

Il existe deux solutions à ce problème:

La première solution consiste à ajouter un constructeur à votre composant et à lier votre fonction comme ci-dessous:

constructor(props) {
        super(props);

        ...

        this.delta = this.delta.bind(this);
    }

Faites donc ceci:

this.delta = this.delta.bind(this); 

Au lieu de cela:

this.delta.bind(this);

La deuxième solution consiste à utiliser une fonction flèche à la place:

delta = () => {
       this.setState({
           count : this.state.count++
      });
   }

En fait, la fonction de flèche ne lie pas la sienne this. Fonctions flèches lexicalement bindleur contexte thisse réfère donc en fait au contexte d'origine .

Pour plus d'informations sur la fonction de liaison:

Fonction Bind Comprendre JavaScript Bind ()

Pour plus d'informations sur la fonction flèche:

Javascript ES6 - Fonctions fléchées et lexical this


1

vous devez lier un nouvel événement avec ce mot - clé comme je le mentionne ci-dessous ...

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count : 1
        };

        this.delta = this.delta.bind(this);
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
      }
    }

1

Ajouter

onClick = {this.delta.bind (this)}

va résoudre le problème. cette erreur survient lorsque nous essayons d'appeler la fonction de la classe ES6, nous devons donc lier la méthode.


1

La fonction flèche aurait pu vous faciliter la vie pour éviter de lier ce mot - clé. Ainsi:

 delta = () => {
       this.setState({
           count : this.state.count++
      });
   }

0

bien que cette question ait déjà une solution, je veux juste partager la mienne pour qu'elle soit clarifiée, j'espère qu'elle pourrait aider:

/* 
 * The root cause is method doesn't in the App's context 
 * so that it can't access other attributes of "this".
 * Below are few ways to define App's method property
 */
class App extends React.Component {
  constructor() {
     this.sayHi = 'hello';
     // create method inside constructor, context = this
     this.method = ()=> {  console.log(this.sayHi) };

     // bind method1 in constructor into context 'this'
     this.method1 = this.method.bind(this)
  }

  // method1 was defined here
  method1() {
      console.log(this.sayHi);
  }

  // create method property by arrow function. I recommend this.
  method2 = () => {
      console.log(this.sayHi);
  }
   render() {
   //....
   }
}

0
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>

    <script src="https://unpkg.com/react@0.14.8/dist/react.min.js"></script>
    <script src="https://unpkg.com/react-dom@0.14.8/dist/react-dom.min.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

  </head>
  <body>
  <div id="root"></div>
    <script type="text/babel">

        class App extends React.Component{

            constructor(props){
                super(props);
                this.state = {
                    counter : 0,
                    isToggle: false
                }
            this.onEventHandler = this.onEventHandler.bind(this);   
            }

            increment = ()=>{
                this.setState({counter:this.state.counter + 1});
            }

            decrement= ()=>{
                if(this.state.counter > 0 ){
                this.setState({counter:this.state.counter - 1});    
                }else{
                this.setState({counter:0});             
                }
            }
            // Either do it as onEventHandler = () => {} with binding with this  // object. 
            onEventHandler(){
                this.setState({isToggle:!this.state.isToggle})
                alert('Hello');
            }


            render(){
                return(
                    <div>
                        <button onClick={this.increment}> Increment </button>
                        <button onClick={this.decrement}> Decrement </button>
                        {this.state.counter}
                        <button onClick={this.onEventHandler}> {this.state.isToggle ? 'Hi':'Ajay'} </button>

                    </div>
                    )
            }
        }
        ReactDOM.render(
        <App/>,
        document.getElementById('root'),
      );
    </script>
  </body>
  </html>

0

Changez simplement votre instruction bind de ce que vous avez à => this.delta = this.delta.bind (this);


0
  1. Vérifier l'état vérifier l'état si vous créez une propriété particulière ou non

this.state = {
            name: "",
            email: ""
            }
            
           
            
this.setState(() => ({ 
             comments: comments          //comments not available in state
             })) 

2. Vérifiez le (this) si vous faites setState dans une fonction (ie handleChange) vérifiez si la fonction est liée à ceci ou si la fonction doit être une fonction de flèche.

## 3 façons de le lier à la fonction ci-dessous ##

//3 ways for binding this to the below function

handleNameChange(e) {  
     this.setState(() => ({ name }))
    }
    
// 1.Bind while callling function
      onChange={this.handleNameChange.bind(this)}
      
      
//2.make it as arrow function
     handleNameChange((e)=> {  
     this.setState(() => ({ name }))
     })
    
//3.Bind in constuctor 

constructor(props) {
        super(props)
        this.state = {
            name: "",
            email: ""
        }
        this.handleNameChange = this.handleNameChange.bind(this)
        }


0

si vous utilisez la syntaxe ES5, vous devez la lier correctement

this.delta = this.delta.bind(this)

et si vous utilisez ES6 et au- dessus , vous pouvez utiliser la fonction flèche, vous n'avez pas besoin d'utiliser bind () , il

delta = () => {
    // do something
  }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.