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.