Dangling_pointer
Dangling_pointer

Reputation: 4743

React - uncaught TypeError: Cannot read property 'setState' of undefined

I am getting the following error

Uncaught TypeError: Cannot read property 'setState' of undefined

even after binding delta in the 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>
        );
    }
}

Upvotes: 453

Views: 440598

Answers (21)

Davin Tryon
Davin Tryon

Reputation: 67296

This is due to this.delta not being bound to this.

Option A: In order to bind set this.delta = this.delta.bind(this) in the constructor:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

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

Currently, you are calling bind. But bind returns a bound function. You need to set the function to its bound value.

Option B: Use an arrow function:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

}

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

Upvotes: 603

yakob abada
yakob abada

Reputation: 1287

Two solutions

one:

    constructor(props) {
        super(props);

        this.state = {
            count : 1
        };

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

two:

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={() => this.delta()}>+</button>
            </div>
        );
    }

Upvotes: 0

Shir Gans
Shir Gans

Reputation: 2027

If anyone is looking for the same sulution when using axios, or any fetch or get, and using setState will return this error.

What you need to do, is to define the component outside, as so:

componentDidMount(){
  let currentComponent = this;
  axios.post(url, Qs.stringify(data))
     .then(function (response) {
          let data = response.data;
          currentComponent.setState({
             notifications : data.notifications
      })
   })
}

Upvotes: 2

Sunil Jakhar
Sunil Jakhar

Reputation: 229

If using inside axios , Use the Arrow(=>) in then

axios.get('abc.com').then((response) => {});

Upvotes: 1

Asgar Ali Khachay
Asgar Ali Khachay

Reputation: 552

if your are using ES5 syntax then you need to bind it properly

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

and if you are using ES6 and above you can use arrow function, then you don't need to use bind() it

delta = () => {
    // do something
  }

Upvotes: 9

Mselmi Ali
Mselmi Ali

Reputation: 1247

There are two solutions of this issue:

The first solution is add a constructor to your component and bind your function like bellow:

constructor(props) {
        super(props);

        ...

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

So do this:

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

Instead of this:

this.delta.bind(this);

The second solution is to use an arrow function instead:

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

Actually arrow function DOES NOT bind it’s own this. Arrow Functions lexically bind their context so this actually refers to the originating context.

For more information about bind function:

Bind function Understanding JavaScript Bind ()

For more information about arrow function:

Javascript ES6 — Arrow Functions and Lexical this

Upvotes: 7

Emeka Augustine
Emeka Augustine

Reputation: 931

Arrow function could have make your life more easier to avoid binding this keyword. Like so:

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

Upvotes: 4

K23raj
K23raj

Reputation: 341

  1. Check state check state whether you create particular property or not

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

2.Check the (this) if you doing setState inside any function (i.e handleChange) check whether the function bind to this or the function should be arrow function .

## 3 ways for binding this to the below function##

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

Upvotes: 1

hardik chugh
hardik chugh

Reputation: 1150

This error can be resolved by various methods-

  • If you are using ES5 syntax, then as per React js Documentation you have to use bind method.

    Something like this for the above example:

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

  • If you are using ES6 syntax,then you need not use bind method,you can do it with something like this:

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

Upvotes: 6

Prashant Yalatwar
Prashant Yalatwar

Reputation: 179

Adding

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

will solve the problem . this error comes when we try to call the function of ES6 class , So we need to bind the method.

Upvotes: 2

Kilo One
Kilo One

Reputation: 21

Just change your bind statement from what you have to => this.delta = this.delta.bind(this);

Upvotes: 2

Neel Patel
Neel Patel

Reputation: 2176

you have to bind new event with this keyword as i mention below...

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

Upvotes: 7

Gabo Ruiz
Gabo Ruiz

Reputation: 556

You dont have to bind anything, Just use Arrow functions like this:

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

Upvotes: 35

Jaroslav Benc
Jaroslav Benc

Reputation: 570

You can also use:

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

Or:

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

If you are passing some params..

Upvotes: 8

Shahrukh Anwar
Shahrukh Anwar

Reputation: 2632

You have to bind your methods with 'this' (default object). So whatever your function may be just bind that in the 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>
    );

Upvotes: 8

Ajay Kumar
Ajay Kumar

Reputation: 5233

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

Upvotes: 2

Fabien Sa
Fabien Sa

Reputation: 9460

In ES7+ (ES2016) you can use the experimental function bind syntax operator :: to bind. It is a syntactic sugar and will do the same as Davin Tryon's answer.

You can then rewrite this.delta = this.delta.bind(this); to this.delta = ::this.delta;


For ES6+ (ES2015) you can also use the ES6+ arrow function (=>) to be able to use this.

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

Why ? From the Mozilla doc :

Until arrow functions, every new function defined its own this value [...]. This proved to be annoying with an object-oriented style of programming.

Arrow functions capture the this value of the enclosing context [...]

Upvotes: 189

Ignatius Andrew
Ignatius Andrew

Reputation: 8258

When using ES6 code in React always use arrow functions, because the this context is automatically binded with it

Use this:

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

instead of:

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

Upvotes: 26

Kai
Kai

Reputation: 3643

though this question had a solution already, I just want to share mine to make it be cleared, hope it could help:

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

Upvotes: 1

Tao Wang
Tao Wang

Reputation: 714

There is a difference of context between ES5 and ES6 class. So, there will be a little difference between the implementations as well.

Here is the 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>
            );
    }
});

and here is the 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>
            );
    }
}

Just be careful, beside the syntax difference in the class implementation, there is a difference in the event handler binding.

In the ES5 version, it's

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

In the ES6 version, it's:

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

Upvotes: 37

Anil
Anil

Reputation: 965

You need to bind this to the constructor and remember that changes to constructor needs restarting the server. Or else, you will end with the same error.

Upvotes: 6

Related Questions