Reaccionar: TypeError no capturado: no se puede leer la propiedad 'setState' de undefined


316

Estoy teniendo el siguiente error

TypeError no capturado: no se puede leer la propiedad 'setState' de undefined

incluso después de enlazar delta en el constructor.

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

44
en ES6, use puede usar la función de flecha para la declaración de función para solucionar este problema.
Tal

^ esta debería ser la respuesta correcta
Jordec

Cambié mi función de respuesta a ES6, y hurrey, está funcionando.
Ashwani Garg

Respuestas:


449

Esto se debe a this.deltano estar obligado a this.

Para enlazar set this.delta = this.delta.bind(this)en el constructor:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

Actualmente, estás llamando a Bind. Pero bind devuelve una función enlazada. Debe establecer la función en su valor límite.


188
¿Cuál es el objetivo de las clases de ES6 si sus métodos no tienen un thisenlace léxico adecuado , y luego ni siquiera exponen una sintaxis para vincular su contexto directamente en su definición?
AgmLauncher

1
Entiendo su punto, pero si escribo código en componentWillMount (), entonces, ¿cómo lo vincularé?
suresh pareek

1
@sureshpareek Una vez que vincula su función en el constructor, debe vincularse cuando la llama desde cualquier enlace de ciclo de vida.
Levi Fuller el

44
Viniendo de android / java world estoy desconcertado
Tudor

3
El uso de @AgmLauncher de las funciones de Lambda lo vincula implícitamente. Si definió deltacomo delta = () => { return this.setState({ count: this.state.count++ }); };el código también funcionaría. Explicado aquí: hackernoon.com/…
K. Rhoda

145

En ES7 + (ES2016) puede usar la función experimental operador de sintaxis:: de enlace para enlazar. Es un azúcar sintáctico y hará lo mismo que la respuesta de Davin Tryon.

Luego puede reescribir this.delta = this.delta.bind(this);athis.delta = ::this.delta;


Para ES6 + (ES2015) también puede usar la función de flecha ES6 + ( =>) para poder usar this.

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

Por qué ? Del documento de Mozilla:

Hasta las funciones de dirección, cada nueva función definida por su propio este valor [...]. Esto resultó ser molesto con un estilo de programación orientado a objetos.

Las funciones de flecha capturan el valor de este del contexto [...]


3
Buen artículo que describe esto en detalle: reactkungfu.com/2015/07/…
Edo

¿Cuál es la ventaja de usar uno sobre el otro, además de la sintaxis?
Jeremy D

2
La sintaxis de enlace es más limpia porque puede mantener el alcance normal de su método.
Fabien Sa

La sintaxis de enlace no forma parte de ES2016 o ES2017.
Felix Kling

2
@stackoverflow debería agregar la capacidad de agregar una recompensa a cualquier respuesta.
Gabe

29

Hay una diferencia de contexto entre las clases ES5 y ES6. Por lo tanto, también habrá una pequeña diferencia entre las implementaciones.

Aquí está la versión 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>
            );
    }
});

y aquí está la versión 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>
            );
    }
}

Solo tenga cuidado, además de la diferencia de sintaxis en la implementación de la clase, hay una diferencia en el enlace del controlador de eventos.

En la versión ES5, es

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

En la versión ES6, es:

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

Usar las funciones de flecha o el enlace en JSX es una mala práctica. stackoverflow.com/questions/36677733/… .
Fabien Sa

24

Al usar el código ES6 en React, siempre use las funciones de flecha, porque este contexto se vincula automáticamente con él

Utilizar este:

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

en vez de:

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

2
Si usa la función de flecha y la variable de parámetro es la misma que la variable clave , recomendaría usarla como this.setState({videos});
jayeshkv

Esto es lo que hizo por mí. Soy nuevo en node, y los documentos para el módulo axios eran incompatibles con react and setState
dabobert el

20

No tiene que vincular nada, solo use las funciones de flecha como esta:

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

eso funciona, ¿cuál es la diferencia, por qué?
Ridha Rezzag

44
El alcance de este con funciones de flecha se hereda del contexto. Con las funciones regulares, esto siempre se refiere a la función más cercana, mientras que con las funciones de flecha este problema se elimina, y no necesitará escribir var that = this nunca más. @RezzagRidha
Gabo Ruiz

1
A partir de 2019, este es el camino a seguir (S)
MH

6

También puedes usar:

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

O:

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

Si estás pasando algunos params ...


Es una mala práctica usar funciones de flecha en JSX
Gabe

5

Debe vincular esto al constructor y recordar que los cambios en el constructor deben reiniciar el servidor. O bien, terminará con el mismo error.


1
Me estaba arrancando el pelo porque no reinicié el servidor.
kurtcorbett

5

Debe vincular sus métodos con 'this' (objeto predeterminado). Entonces, cualquiera que sea su función, solo agréguela al constructor.

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

Este error puede resolverse por varios métodos:

  • Si está utilizando la sintaxis de ES5 , entonces, según la documentación de React js , debe utilizar el método de enlace .

    Algo como esto para el ejemplo anterior:

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

  • Si está utilizando la sintaxis de ES6 , entonces no necesita utilizar el método de enlace , puede hacerlo con algo como esto:

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


2

Hay dos soluciones a este problema:

La primera solución es agregar un constructor a su componente y vincular su función como se muestra a continuación:

constructor(props) {
        super(props);

        ...

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

Entonces haz esto:

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

En lugar de esto:

this.delta.bind(this);

La segunda solución es usar una función de flecha en su lugar:

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

En realidad, la función de flecha NO se une a sí misma this. Las funciones de flecha léxicamente bindsu contexto, por lo que en thisrealidad se refiere al contexto de origen .

Para más información sobre la función de enlace:

Función de enlace Comprender JavaScript Bind ()

Para más información sobre la función de flecha:

Javascript ES6 - Funciones de flecha y léxico this


1

tienes que vincular un nuevo evento con esta palabra clave como menciono a continuación ...

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

Agregando

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

Resolverá el problema. Este error se produce cuando intentamos llamar a la función de la clase ES6, por lo que debemos vincular el método.


1

La función de flecha podría haber hecho su vida más fácil para evitar vincular esta palabra clave. Al igual que:

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

0

Aunque esta pregunta ya tenía una solución, solo quiero compartir la mía para que se aclare, espero que pueda ayudar:

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

Simplemente cambie su declaración de vinculación de lo que tiene que => this.delta = this.delta.bind (this);


0
  1. Verificar estado verificar estado si creas una propiedad particular o no

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

2. Verifique (esto) si está haciendo setState dentro de cualquier función (es decir, handleChange), verifique si la función se une a esto o si la función debería ser una función de flecha.

## 3 formas de vincular esto a la siguiente función ##

//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 está utilizando la sintaxis de ES5, debe vincularla correctamente

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

y si está utilizando ES6 y por encima de usted puede utilizar la función de flecha, entonces no es necesario el uso bind () se

delta = () => {
    // do something
  }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.