React - uncaught TypeError: Die Eigenschaft 'setState' von undefined kann nicht gelesen werden

316

Ich erhalte den folgenden Fehler

Nicht erfasster TypeError: Die Eigenschaft 'setState' von undefined kann nicht gelesen werden

auch nach Bindung von Delta im Konstruktor.

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>
        );
    }
}
Dangling_pointer
quelle
4
Verwenden Sie in ES6 die Pfeilfunktion für die Funktionsdeklaration, um dieses Problem zu beheben.
Tal
^ Dies sollte die richtige Antwort sein
Jordec
Ich habe meine Antwortfunktion in ES6 geändert und Hurrey, es funktioniert.
Ashwani Garg

Antworten:

448

Dies liegt daran, this.deltanicht gebunden zu seinthis .

So binden Sie set this.delta = this.delta.bind(this)im Konstruktor:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

Derzeit rufen Sie bind auf. Bind gibt jedoch eine gebundene Funktion zurück. Sie müssen die Funktion auf ihren gebundenen Wert setzen.

Davin Tryon
quelle
186
Was um alles in der Welt ist der Sinn von ES6-Klassen, wenn ihre Methoden keine ordnungsgemäße lexikalische thisBindung haben und dann nicht einmal eine Syntax für die direkte Bindung ihres Kontexts an ihre Definition verfügbar machen?
AgmLauncher
1
Ich verstehe Ihren Punkt, aber wenn ich Code in componentWillMount () schreibe, wie werde ich dann binden
suresh pareek
1
@sureshpareek Sobald Sie Ihre Funktion im Konstruktor gebunden haben, sollte sie gebunden sein, wenn Sie sie von einem beliebigen Lebenszyklus-Hook aus aufrufen.
Levi Fuller
4
Ich komme aus der Android / Java-Welt und bin verblüfft
Tudor
3
Die Verwendung von Lambda-Funktionen durch @AgmLauncher bindet dies implizit. Wenn Sie deltaals delta = () => { return this.setState({ count: this.state.count++ }); };Code definiert würden, würde auch funktionieren. Hier erklärt: hackernoon.com/…
K. Rhoda
144

In ES7 + (ES2016) können Sie die experimentelle Verwendung Funktion bind Syntax Operator:: zu binden. Es ist ein syntaktischer Zucker und wird das Gleiche tun wie Davin Tryons Antwort.

Sie können dann umschreiben this.delta = this.delta.bind(this);zuthis.delta = ::this.delta;


Für ES6 + (ES2015) Sie können auch die ES6 verwenden + Pfeil - Funktion ( =>) verwenden zu können this.

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

Warum ? Aus dem Mozilla-Dokument:

Bis Pfeil Funktionen, definiert jede neue Funktion seine eigene diese Wert [...]. Dies erwies sich bei einem objektorientierten Programmierstil als ärgerlich.

Pfeilfunktionen erfassen diesen Wert des einschließenden Kontextes [...]

Fabien Sa.
quelle
3
Schöner Artikel, der dies ausführlich beschreibt: reactkungfu.com/2015/07/…
Edo
Was ist der Vorteil der Verwendung übereinander neben der Syntax?
Jeremy D
2
Die Bindungssyntax ist sauberer, da Sie den normalen Umfang Ihrer Methode beibehalten können.
Fabien Sa
Die Bindungssyntax ist nicht Teil von ES2016 oder ES2017.
Felix Kling
2
@stackoverflow sollte die Möglichkeit hinzufügen, jeder Antwort ein Kopfgeld hinzuzufügen.
Gabe
29

Es gibt einen Kontextunterschied zwischen der ES5- und der ES6-Klasse. Es wird also auch einen kleinen Unterschied zwischen den Implementierungen geben.

Hier ist die ES5-Version:

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>
            );
    }
});

und hier ist die ES6-Version:

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>
            );
    }
}

Seien Sie vorsichtig, neben dem Syntaxunterschied in der Klassenimplementierung gibt es einen Unterschied in der Bindung des Ereignishandlers.

In der ES5-Version ist es

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

In der ES6-Version ist es:

              <button onClick={this.delta.bind(this)}>+</button>
Tao Wang
quelle
Die Verwendung von Pfeilfunktionen oder das Binden in JSX ist eine schlechte Praxis. stackoverflow.com/questions/36677733/… .
Fabien Sa
24

Verwenden Sie bei der Verwendung von ES6-Code in React immer Pfeilfunktionen , da dieser Kontext automatisch damit verbunden wird

Benutze das:

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

anstatt:

function(videos) {
    this.setState({ videos: videos });
    console.log(this.state.videos);
};
Ignatius Andrew
quelle
2
Wenn die Verwendung der Pfeilfunktion und der Parametervariablen mit der Schlüsselvariablen identisch ist , würde ich empfehlen, sie als this.setState({videos});
jayeshkv
Das hat es für mich getan. Ich bin neu in Node, und die Dokumente für das Axios-Modul waren nicht kompatibel mit React und SetState
Dabobert
20

Sie müssen nichts binden. Verwenden Sie einfach die Pfeilfunktionen wie folgt:

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>
        );
    }
}
Gabo Ruiz
quelle
das funktioniert was ist der Unterschied bitte warum ist das so?
Ridha Rezzag
4
Der Bereich mit Pfeilfunktionen wird vom Kontext geerbt. Bei regulären Funktionen bezieht sich dies immer auf die nächstgelegene Funktion, während bei Pfeilfunktionen dieses Problem behoben ist und Sie nie wieder var that = this schreiben müssen. @RezzagRidha
Gabo Ruiz
1
Ab 2019 ist dies der richtige Weg (Y)
MH
6

Sie können auch verwenden:

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

Oder:

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

Wenn Sie einige Parameter übergeben ..

Jaroslav Benc
quelle
Es ist eine schlechte Praxis, Pfeilfunktionen in JSX
Gabe
5

Sie müssen dies an den Konstruktor binden und sich daran erinnern, dass Änderungen am Konstruktor einen Neustart des Servers erfordern. Andernfalls wird derselbe Fehler angezeigt.

Anil
quelle
1
Ich habe mir die Haare ausgezogen, weil ich den Server nicht neu gestartet habe.
Kurtcorbett
5

Sie müssen Ihre Methoden mit 'this' (Standardobjekt) binden. Was auch immer Ihre Funktion sein mag, binden Sie sie einfach in den Konstruktor.

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>
    );
Shahrukh Anwar
quelle
4

Dieser Fehler kann mit verschiedenen Methoden behoben werden.

  • Wenn Sie die ES5- Syntax verwenden, müssen Sie gemäß React js Documentation bind verwenden - Methode.

    So etwas für das obige Beispiel:

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

  • Wenn Sie mit ES6 Syntax, dann müssen Sie nicht verwenden bind Methode, können Sie es mit so etwas wie dies tun:

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

Hardik Chugh
quelle
2

Es gibt zwei Lösungen für dieses Problem:

Die erste Lösung besteht darin, Ihrer Komponente einen Konstruktor hinzuzufügen und Ihre Funktion wie folgt zu binden:

constructor(props) {
        super(props);

        ...

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

Also mach das:

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

An Stelle von:

this.delta.bind(this);

Die zweite Lösung besteht darin, stattdessen eine Pfeilfunktion zu verwenden:

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

Tatsächlich bindet die Pfeilfunktion NICHT ihre eigene this. Pfeilfunktionen lexikalisch bezieht sich bindihr Kontext also thistatsächlich auf den Ursprungskontext .

Weitere Informationen zur Bindefunktion:

Bindungsfunktion Grundlegendes zur JavaScript-Bindung ()

Weitere Informationen zur Pfeilfunktion:

Javascript ES6 - Pfeilfunktionen und Lexikalisch this

Mselmi Ali
quelle
1

Sie müssen ein neues Ereignis mit diesem Schlüsselwort binden, wie ich unten erwähne ...

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>
        );
      }
    }
Neel Patel
quelle
1

Hinzufügen

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

wird das Problem lösen. Dieser Fehler tritt auf, wenn wir versuchen, die Funktion der ES6-Klasse aufzurufen. Daher müssen wir die Methode binden.

Prashant Yalatwar
quelle
1

Die Pfeilfunktion hätte Ihnen das Leben erleichtern können, um das Binden dieses Schlüsselworts zu vermeiden . Wie so:

 delta = () => {
       this.setState({
           count : this.state.count++
      });
   }
Emeka Augustine
quelle
0

Obwohl diese Frage bereits eine Lösung hatte, möchte ich meine nur teilen, damit sie geklärt wird. Ich hoffe, sie könnte helfen:

/* 
 * 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() {
   //....
   }
}
Kai
quelle
0
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>

    <script src="https://unpkg.com/[email protected]/dist/react.min.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/react-dom.min.js"></script>
    <script src="https://unpkg.com/[email protected]/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>
Ajay Kumar
quelle
0

Ändern Sie einfach Ihre bind-Anweisung von dem, was Sie müssen => this.delta = this.delta.bind (this);

Kilo Eins
quelle
0
  1. Status überprüfen Status überprüfen, ob Sie eine bestimmte Eigenschaft erstellen oder nicht

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

2. Überprüfen Sie (dies), wenn Sie setState in einer Funktion ausführen (z. B. handleChange). Überprüfen Sie, ob die Funktion an diese gebunden ist oder ob die Funktion eine Pfeilfunktion sein soll.

## 3 Möglichkeiten, dies an die folgende Funktion zu binden ##

//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)
        }

K23raj
quelle
0

Wenn Sie die ES5-Syntax verwenden, müssen Sie sie ordnungsgemäß binden

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

und wenn Sie ES6 verwenden und oben können Sie Pfeil - Funktion verwenden, dann müssen Sie nicht verwenden müssen bind () es

delta = () => {
    // do something
  }
Asgar Ali Khachay
quelle