React - uncaught TypeError: impossibile leggere la proprietà 'setState' di undefined


316

Ricevo il seguente errore

Uncaught TypeError: impossibile leggere la proprietà 'setState' di undefined

anche dopo aver associato il delta nel costruttore.

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
in ES6, è possibile utilizzare la funzione freccia per la dichiarazione di funzione per risolvere questo problema.
Tal

^ questa dovrebbe essere la risposta corretta
Jordec il

Ho cambiato la mia funzione di risposta in ES6 e Hurrey, funzionando.
Ashwani Garg,

Risposte:


449

Ciò è dovuto al fatto di this.deltanon essere vincolati a this.

Per associare set this.delta = this.delta.bind(this)nel costruttore:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

Attualmente stai chiamando bind. Ma bind restituisce una funzione associata. È necessario impostare la funzione sul valore associato.


188
Qual è il punto delle classi ES6 se i loro metodi non hanno un corretto thislegame lessicale , e quindi non espongono nemmeno una sintassi per legare il loro contesto direttamente alla loro definizione !?
AgmLauncher,

1
capisco il tuo punto, ma se scrivo il codice in componentWillMount (), allora come
legherò

1
@sureshpareek Dopo aver associato la funzione al costruttore, questa dovrebbe essere associata quando la si chiama da qualsiasi hook del ciclo di vita.
Levi Fuller,

4
Vengo dal mondo Android / Java Sono sconcertato
Tudor

3
L'uso di @AgmLauncher delle funzioni Lambda lo associa implicitamente. Se hai definito deltacome delta = () => { return this.setState({ count: this.state.count++ }); };il codice funzionerebbe anche. Spiegato qui: hackernoon.com/…
K. Rhoda

145

In ES7 + (ES2016) è possibile utilizzare l' operatore di sintassi del bind della funzione sperimentale ::per eseguire il bind. È uno zucchero sintattico e farà lo stesso della risposta di Davin Tryon.

È quindi possibile riscrivere this.delta = this.delta.bind(this);athis.delta = ::this.delta;


Per ES6 + (ES2015) è anche possibile utilizzare la funzione freccia ES6 + ( =>) per poterlo utilizzare this.

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

Perché ? Dal documento Mozilla:

Fino a funzioni di direzione, ogni nuova funzione definita proprio questo valore di [...]. Ciò si è rivelato fastidioso con uno stile di programmazione orientato agli oggetti.

Le funzioni freccia catturano questo valore del contesto racchiuso [...]



Qual è il vantaggio di usare l'uno rispetto all'altro, oltre alla sintassi?
Jeremy D,

2
La sintassi del bind è più chiara perché è possibile mantenere l'ambito normale del metodo.
Fabien Sa

La sintassi di bind non fa parte di ES2016 o ES2017.
Felix Kling,

2
@stackoverflow dovrebbe aggiungere la possibilità di aggiungere una taglia a qualsiasi risposta.
Gabe,

29

Esiste una differenza di contesto tra la classe ES5 e la classe ES6. Quindi, ci sarà anche una piccola differenza tra le implementazioni.

Ecco la versione 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>
            );
    }
});

ed ecco la versione 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>
            );
    }
}

Fai solo attenzione, oltre alla differenza di sintassi nell'implementazione della classe, c'è una differenza nell'associazione del gestore eventi.

Nella versione ES5, lo è

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

Nella versione ES6, è:

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

L'uso delle funzioni freccia o dell'associazione in JSX è una cattiva pratica. stackoverflow.com/questions/36677733/… .
Fabien Sa

24

Quando si utilizza il codice ES6 in React, utilizzare sempre le funzioni freccia, poiché questo contesto viene automaticamente associato a esso

Usa questo:

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

invece di:

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

2
Se si utilizza la funzione freccia e la variabile del parametro è uguale alla variabile chiave , si consiglia di utilizzarla come this.setState({videos});
jayeshkv

Questo è quello che ha fatto per me. Sono nuovo di nodo, e i documenti per il modulo axios erano incompatibili con reagire e impostareState
dabobert

20

Non devi vincolare nulla, basta usare le funzioni Arrow in questo modo:

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

che funziona qual è la differenza, per favore, perché?
Ridha Rezzag,

4
Questo ambito con funzioni freccia è ereditato dal contesto. Con le funzioni regolari, questo si riferisce sempre alla funzione più vicina, mentre con le funzioni freccia questo problema viene rimosso e non sarà più necessario scrivere var che = questo. @RezzagRidha
Gabo Ruiz,

1
A partire dal 2019 questa è la strada da percorrere (Y)
MH,

6

Puoi anche usare:

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

O:

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

Se stai passando alcuni parametri ...


È una cattiva pratica utilizzare le funzioni freccia in JSX
Gabe,

5

È necessario associarlo al costruttore e ricordare che le modifiche al costruttore devono riavviare il server. Altrimenti, finirai con lo stesso errore.


1
Mi stavo togliendo i capelli perché non avevo riavviato il server.
Kurtcorbett,

5

Devi associare i tuoi metodi a 'this' (oggetto predefinito). Quindi, qualunque sia la tua funzione, puoi semplicemente associarla al costruttore.

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

Questo errore può essere risolto con vari metodi:

  • Se stai usando la sintassi ES5 , allora secondo la documentazione di React js devi usare il metodo bind .

    Qualcosa del genere per l'esempio sopra:

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

  • Se si utilizza la sintassi ES6 , non è necessario utilizzare il metodo bind , è possibile farlo con qualcosa del genere:

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


2

Esistono due soluzioni di questo problema:

La prima soluzione è aggiungere un costruttore al componente e associare la funzione come qui sotto:

constructor(props) {
        super(props);

        ...

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

Quindi fai questo:

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

Invece di questo:

this.delta.bind(this);

La seconda soluzione è invece utilizzare una funzione freccia:

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

In realtà la funzione freccia NON si lega da sola this. La freccia funziona in modo lessicale rispetto bindal contesto, quindi si thisriferisce effettivamente al contesto di origine .

Per ulteriori informazioni sulla funzione di associazione:

Funzione Bind Comprensione di JavaScript Bind ()

Per ulteriori informazioni sulla funzione freccia:

Javascript ES6 - Funzioni freccia e lessico this


1

devi associare un nuovo evento con questa parola chiave, come menziono di seguito ...

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

Aggiunta

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

risolverà il problema. questo errore arriva quando proviamo a chiamare la funzione della classe ES6, quindi dobbiamo associare il metodo.


1

La funzione freccia potrebbe aver semplificato la vita per evitare di associare questa parola chiave. Così:

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

0

sebbene questa domanda avesse già una soluzione, voglio solo condividere la mia per farla cancellare, spero che possa aiutare:

/* 
 * 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

Basta cambiare la tua istruzione bind da quello che devi = = this.delta = this.delta.bind (this);


0
  1. Verifica stato Verifica stato se si crea o meno una particolare proprietà

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

2. Controllare (questo) se si sta eseguendo setState all'interno di una funzione (ad esempio handleChange), verificare se la funzione si lega a questa o se la funzione deve essere la funzione freccia.

## 3 modi per associare questo alla funzione sottostante ##

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

se si utilizza la sintassi ES5, è necessario associarla correttamente

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

e se si sta utilizzando ES6 e soprattutto si può usare la funzione freccia, allora non c'è bisogno di utilizzare bind () è

delta = () => {
    // do something
  }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.