0

I am trying to create a counter button but I can't. I know its something to do with binding but I can't find a solution. I tried by using .bind(this) but its does not work.

class Button extends React.Component{
  render(){
    return(
      <button onClick={this.props.localHandleClick}>+1</button>
    )
  }
}
class Result extends React.Component{
  render(){
    return (
      <div>{this.props.localCounter}</div>
    )
      
  }
}
class Main extends React.Component{
  constructor(props){
    super(props);
    this.state={
      counter:0
    }
  }
   clickHandler(){
    this.setState({counter:                   
    this.state.counter+1});
  }
  render(){
    return(
      <div>
        <Button localHandleClick={this.handleClick}/>
        <Result localCounter={this.state.counter} />        
      </div>
    )
      
  }
}
ReactDOM.render(
  <Main />,
  document.getElementById("app")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Krishna Rana
  • 359
  • 1
  • 2
  • 11

2 Answers2

1

Changes:

1. Bind handleClick method in the constructor of main component.

2. There is a name mismatch, you are passing the handleClick method but you defined the clickHandler. Replace clickHandler by handleClick.

Check the working snippet:

class Button extends React.Component{
  render(){
    return(
      <button onClick={this.props.localHandleClick}>+1</button>
    )
  }
}

class Result extends React.Component{
  render(){
    return (
      <div>{this.props.localCounter}</div>
    )
      
  }
}

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

  handleClick(){
    this.setState({counter: this.state.counter+1});
  }

  render(){
    return(
      <div>
        <Button localHandleClick={this.handleClick}/>
        <Result localCounter={this.state.counter} />     
      </div>
    )
      
  }
}

ReactDOM.render(
  <Main />,
  document.getElementById("app")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'/>
Mayank Shukla
  • 92,299
  • 16
  • 152
  • 142
0

Just use .bind(this) on your handler so that this refers to the component instead of being undefined.

Note this is not specific to React, but the default behaviour of JavaScript class methods, which are not automatically bound.

Also, you are using different names in the handler definition and when you use it in the template.

class Button extends React.Component {

  render() {
    return(
      <button onClick={this.props.localHandleClick}>+1</button>
    );
  }
}

class Result extends React.Component {

  render() {
    return(
      <div>{this.props.localCounter}</div>
    );  
  }
}

class Main extends React.Component {

  constructor(props) {
    super(props);
    
    this.state = {
      counter: 0,
    };
    
    this.handleClick = this.handleClick.bind(this)
  }
  
  handleClick() {
    this.setState({
      counter: this.state.counter + 1,
    });
  }
  
  render() {
    return(
      <div>
        <Button localHandleClick={ this.handleClick }/>
        <Result localCounter={ this.state.counter } />        
      </div>
    );
  }
}

ReactDOM.render(<Main />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>

If you are using Babel's class property transform, you can declare your handler as follows, and it will be automatically bound:

class Main extends React.Component {

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

    constructor(props) { ... }

    render() { ... }
}
Danziger
  • 16,123
  • 4
  • 41
  • 70