React - TypeError não capturado: não é possível ler a propriedade 'setState' de undefined

316

Eu estou recebendo o seguinte erro

TypeError não capturado: Não é possível ler a propriedade 'setState' de undefined

mesmo após a ligação delta no construtor.

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
fonte
4
no ES6, você pode usar a função de seta para declaração de função para corrigir esse problema.
Tal
^ esta deve ser a resposta correta
Jordec 26/02
Alterei minha função de resposta para ES6 e hurrey, está funcionando.
Ashwani Garg

Respostas:

449

Isso ocorre porque this.deltanão está vinculado this.

Para ligar o conjunto this.delta = this.delta.bind(this)no construtor:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

Atualmente, você está chamando bind. Mas bind retorna uma função vinculada. Você precisa definir a função para seu valor vinculado.

Davin Tryon
fonte
187
Qual é o sentido das classes ES6 se seus métodos não tiverem uma thisligação lexical adequada e nem sequer expuserem uma sintaxe para vincular seu contexto diretamente à sua definição !?
AgmLauncher
1
Eu entendo o seu ponto, mas se eu escrever código em componentWillMount (), então como vou ligar
suresh pareek
1
@sureshpareek Depois de vincular sua função no construtor, ela deverá ser vinculada quando você a chamar de qualquer gancho do ciclo de vida.
Levi Fuller
4
Vindo de mundo / java android Estou perplexo
Tudor
3
O uso das funções Lambda pelo @AgmLauncher vincula isso implicitamente. Se você definiu deltacomo delta = () => { return this.setState({ count: this.state.count++ }); };o código também funcionaria. Explicado aqui: hackernoon.com/…
K. Rhoda
145

No ES7 + (ES2016), você pode usar o operador de sintaxe de ligação da função experimental ::para ligar. É um açúcar sintático e fará o mesmo que a resposta de Davin Tryon.

Você pode reescrever this.delta = this.delta.bind(this);parathis.delta = ::this.delta;


Para o ES6 + (ES2015), você também pode usar a função de seta do ES6 + ( =>) para poder usá-lo this.

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

Por quê ? No documento Mozilla:

Até funções de seta, cada nova função definida a sua própria este valor [...]. Isso provou ser irritante com um estilo de programação orientado a objetos.

As funções de seta capturam o valor este do contexto anexo [...]

Fabien Sa
fonte
3
Bom artigo que descreve isso em detalhes: reactkungfu.com/2015/07/…
Edo
Qual é a vantagem de usar um sobre o outro, além da sintaxe?
Jeremy D
2
A sintaxe de ligação é mais limpa, porque você pode manter o escopo normal do seu método.
Fabian Sa
A sintaxe de ligação não faz parte do ES2016 ou ES2017.
Felix Kling
2
O @stackoverflow deve adicionar a capacidade de adicionar uma recompensa a qualquer resposta.
Gabe
29

Há uma diferença de contexto entre a classe ES5 e ES6. Portanto, haverá uma pequena diferença entre as implementações também.

Aqui está a versão do 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>
            );
    }
});

e aqui está a versão 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>
            );
    }
}

Apenas tome cuidado, além da diferença de sintaxe na implementação da classe, há uma diferença na ligação do manipulador de eventos.

Na versão ES5, é

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

Na versão ES6, é:

              <button onClick={this.delta.bind(this)}>+</button>
Tao Wang
fonte
Usar funções de seta ou ligação no JSX é uma prática ruim. stackoverflow.com/questions/36677733/… .
Fabian Sa
24

Ao usar o código ES6 no React, use sempre as funções de seta, porque este contexto é vinculado automaticamente a ele

Usa isto:

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

ao invés de:

function(videos) {
    this.setState({ videos: videos });
    console.log(this.state.videos);
};
Inácio André
fonte
2
Se usar a função de seta e a variável de parâmetro for a mesma que a variável-chave , eu recomendaria usá-la como this.setState({videos});
jayeshkv
Foi isso que fez por mim. Eu sou novo para nós, e a documentação para o módulo Axios era incompatível com reagir e setState
dabobert
20

Você não precisa vincular nada, basta usar as funções de seta assim:

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
fonte
isso funciona qual é a diferença por favor porque é isso?
Ridha Rezzag 04/11
4
As funções deste escopo com seta são herdadas do contexto. Com funções regulares, isso sempre se refere à função mais próxima, enquanto que com funções de seta esse problema é removido e você não precisará escrever var that = this novamente. @RezzagRidha
Gabo Ruiz
1
A partir de 2019, este é o caminho a seguir (Y)
MH
6

Você também pode usar:

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

Ou:

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

Se você está passando alguns params ..

Jaroslav Benc
fonte
É má prática para funções uso de seta em JSX
Gabe
5

Você precisa vincular isso ao construtor e lembre-se de que as alterações no construtor precisam reiniciar o servidor. Ou então, você terminará com o mesmo erro.

Anil
fonte
1
Estava puxando meu cabelo porque não reiniciei o servidor.
precisa saber é o seguinte
5

Você precisa vincular seus métodos com 'this' (objeto padrão). Portanto, seja qual for a sua função, basta vincular isso ao construtor.

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
fonte
4

Este erro pode ser resolvido por vários métodos -

  • Se você estiver usando a sintaxe do ES5 , conforme a Documentação do React js, será necessário usar o método de ligação .

    Algo assim para o exemplo acima:

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

  • Se você estiver usando a sintaxe ES6 , não precisará usar o método bind , poderá fazê-lo com algo como isto:

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

gargalhada
fonte
2

Existem duas soluções para esse problema:

A primeira solução é adicionar um construtor ao seu componente e vincular sua função como abaixo:

constructor(props) {
        super(props);

        ...

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

Então faça o seguinte:

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

Em vez disso:

this.delta.bind(this);

A segunda solução é usar uma função de seta:

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

Na verdade, a função de seta NÃO vincula a si própria this. As funções de seta lexicamente bindseu contexto, portanto, thisna verdade, se refere ao contexto de origem .

Para mais informações sobre a função de ligação:

Função de ligação Noções básicas sobre JavaScript Bind ()

Para mais informações sobre a função de seta:

Javascript ES6 - Funções de seta e Lexical this

Mselmi Ali
fonte
1

você deve vincular um novo evento a essa palavra - chave, como mencionei abaixo ...

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
fonte
1

Adicionando

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

vai resolver o problema. esse erro ocorre quando tentamos chamar a função da classe ES6, portanto, precisamos vincular o método

Prashant Yalatwar
fonte
1

A função de seta poderia facilitar sua vida para evitar vincular essa palavra - chave. Igual a:

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

Embora essa pergunta já tenha uma solução, eu só quero compartilhar a minha para que fique clara, espero que possa ajudar:

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

Apenas mude sua instrução bind do que você precisa => this.delta = this.delta.bind (this);

Kilo One
fonte
0
  1. Estado de verificação estado de verificação se você cria uma propriedade específica ou não

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

2. Marque a opção (this) se estiver executando o setState em alguma função (por exemplo, handleChange), verifique se a função está vinculada a esta ou à função deve ser a função de seta.

## 3 maneiras de vincular isso à função abaixo ##

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

se você estiver usando a sintaxe ES5, precisará vinculá-lo corretamente

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

e se você estiver usando ES6 e acima, você pode usar a seta função, então você não precisa usar bind () que

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