Sunil Tripathi
Sunil Tripathi

Reputation: 616

"this" is not defined in event handlers

why this is not defined in function increaseCounter but is defined in getBadgeClass function ?

<button onClick = { this.increaseCounter } className = { 
this.getBadgeClasses() }>increment</button>

getBadgeClasses() {         
    let classes = "badge m-2 badge-";
    classes += this.state.count === 0 ? "warning" : "primary";
    return classes;
}

 increaseCounter(){
    this.state.count++;
}

Upvotes: 1

Views: 2916

Answers (5)

A B M Nasim
A B M Nasim

Reputation: 1

There are two parts to this error. The first is that the error handler must be defined like this, in order to make this work correctly with the error function:

increaseCounter = () => { ... }

The second part of the problem is that you can't change the state directly; instead, you must change the state using this.setState():

increaseCounter = () => {
    this.setState(prevState => {
        return {count: prevState.count + 1}
    }
}

Upvotes: 0

bhagya
bhagya

Reputation: 23

In addition to what Shahrukh has mentioned, in strict mode global object refers to undefined in place of the window object. So when the function increaseCounter() is called on global object, it calls on an undefined object.
Also, when a function is used as an event handler, its 'this' is set to the element the event fired from. As a DOM event handler. Therefore, increaseCounter()'s this is set to global context.
Since in JavaScript class methods are not bound by default unless you specifically bind them, they are just "function objects". Any object or variable can reference the function because it's just a pointer, like any other object. The question asked is actually to be blamed on JavaScript, not React.js.

Upvotes: 0

vladpopovv
vladpopovv

Reputation: 141

You should bind function which uses this. To save this context you can use one of these ways: 1) Bind functions in the constructor:

constructor(props) {
  super(props);

  this.getBadgeClasses = this.getBadgeClasses.bind(this);
  this.increaseCounter = this.increaseCounter.bind(this);
}

2) Or you can use arrow function. It saves this context as well:

increaseCounter = () => {
 ...your code
}

You can read more here: https://medium.com/silesis/handle-events-in-react-with-arrow-functions-ede88184bbb#4803

Upvotes: 6

Vikash_Singh
Vikash_Singh

Reputation: 1896

you have to bind this to increaseCounter function to access this object. Do this :

<button onClick = { this.increaseCounter.bind(this) } 
        className = { this.getBadgeClasses.bind(this) }
>
    increment
</button>

Upvotes: 0

Shahrukh Haider
Shahrukh Haider

Reputation: 474

When the interpreter reaches the component, this.getBadgeClasses() executes right away. It is called on the object referred by this so the keyword this inside the function, points to the same object. So it is able to resolve the reference to the state.

On the other hand, this.increaseCounter() does not execute right away. The attribute onClick just stores a reference to that function. Whenever a user clicks on the button, that referenced function is called on the global object. So the keyword this is set to undefined in the strict mode. To resolve this, you have to bind the increaseCounter() to this in the constructor.

Upvotes: 1

Related Questions