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

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.


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 [...]


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>

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

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

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 ..


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.


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

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


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


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

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.


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

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() {
   //....
   }
}

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

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


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


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
  }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.