kokserek
kokserek

Reputation: 579

How to make the button interactive in React.js?

Please point me to my error.

I want to write an interactive button that displays the number of clicks on it. With each next click, the number on the button have to increase by one. Initial number is 0, so, for example, after 5 clicks it becomes 5. Without an interactive element, the code is rendered normally.

Here is my code:

class Button extends React.Component{
  constructor(props){
    super(props);
    this.state = {counter: 0};
  };

  handleClick(){
    this.setState(
      prevState => ({counter: prevState.counter + 1})
    );
  }

  render(){
    return (
      <button onClick={this.handleClick}>{this.state.counter}</button>
    );
  }
}

Here is the error I get:

TypeError: Cannot read property 'setState' of undefined
handleClick
src/index.js:30:6
  27 | 
  28 |   render(){
  29 |     return (
> 30 |       <button onClick={this.handleClick}>{this.state.counter}</button>
     |      ^  31 |     );
  32 |   }
  33 | }
View compiled
▶ 20 stack frames were collapsed.

Thank you in advance!

Upvotes: 3

Views: 1343

Answers (4)

Vencovsky
Vencovsky

Reputation: 31683

You could go a little bit more advanced and use the ECMAScript 6 arrow function syntax, which will avoid that kind of problem and also avoid the need to use .bind(this).

If you declare handleClick like handleClick = () => {}, you wont need to use in your constructor this.handleClick.bind(this). Everything will work normally when you use this, it will be the class's this, not the function's this.

This is using newer versions of javascript and is highly recommended to don't use .bind(this) which can cause some issues.

Just declare handleClick like this and it will work without the need to use .bind(this)

  handleClick = () => {
    this.setState(
      prevState => ({counter: prevState.counter + 1})
    );
  }

Upvotes: 2

spinyBabbler
spinyBabbler

Reputation: 407

I think you have two options:

  1. Add bind to your constructor. this.handleClick.bind(this), which will ensure that your this actually refers to the button object.
  2. Use newer format, which I like better.

    handleClick = () => {
        this.setState(
            prevState => ({counter: prevState.counter + 1})
        );
    }
    

A little more helpful documentation on a lot of React topics here: https://reactjs.org/docs/react-component.html

Upvotes: 1

tobbe
tobbe

Reputation: 1807

You have to bind the click handler:

...
  constructor(props){
    super(props);
    this.state = {counter: 0};
    this.handleClick.bind(this) // <----- here
  }
...

Upvotes: 1

Chris Sandvik
Chris Sandvik

Reputation: 1927

In your example, this in your handleClick() function refers to the scope of the event that was fired from your click. In order to solve this you must bind the functions scope to the element.

Add this.handleClick = this.handleClick.bind(this) to your constructor and it should work fine.

https://reactjs.org/docs/handling-events.html

Upvotes: 4

Related Questions