TheLearner
TheLearner

Reputation: 2863

"Cannot read property 'onClick' of undefined" in React component

I am using Reactstrap in my project for Bootstrap integration. However, I also need to extend the onClick behavior of the Button component that comes out of the box with Reactstrap. To that end, I have made a custom NanoButton component that recomposes the default one. This is how I'm calling it:

<NanoButton type="button" onClick={() => Router.push('/about')}>About</NanoButton>

The NanoButton component, as I said, adds my custom onClick functionality to the existing Button class:

import { Component } from 'react';
import { Button } from 'reactstrap';

class NanoButton extends Component {
  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
  }
  onClick(e) {
        var circle = document.createElement('div');
        e.target.appendChild(circle);
        var d = Math.max(e.target.clientWidth, e.target.clientHeight);
        circle.style.width = circle.style.height = d + 'px';
        var rect = e.target.getBoundingClientRect();
        circle.style.left = e.clientX - rect.left -d/2 + 'px';
        circle.style.top = e.clientY - rect.top - d/2 + 'px';
        circle.classList.add('ripple');

        this.props.onClick();
  }
  render() {
    return (
      <Button
        className={this.props.className}
        type={this.props.type}
        color={this.props.color}
        size={this.props.size}
        onClick={this.onClick}
      >
        {this.props.children}
      </Button>
    );
  }
}

export default NanoButton;

As you can see, I need the NanoButton component to perform some custom activities before finally executing the onClick function passed to it as the prop. But when loading in browser, it fails at this.props.onClick(); saying it cannot read onClick on undefined? What could I be missing here?

Upvotes: 1

Views: 11121

Answers (3)

Vinit Raj
Vinit Raj

Reputation: 1910

This occurs when this is not defined in the function context,So for solving that You just need to bind this action, So for doing that you can bind this either in your constructor method or you can directly bind this with the function whenever it is passed as props in the render function.

Binding directly in Constructor

constructor(props){
 super(props);
 this.onClick = this.onClick.bind(this);
}

Passing as a props:-

<Button onClick={this.onClick.bind(this)/>

Upvotes: 3

ncubica
ncubica

Reputation: 8475

if you want to forget about when to bind or not your methods you can replace the following style:

onClick(e) {

}

with:

onClick = (e) => {
  this.props.onClick();
}

and the arrow function will automatically bind everything for you, you don't need to change your code only the way you define these methods.

the reason of onClick on undefined error is because indeed onClick is defined in the scope of the Dom element which lacks the onClick method definition.

Upvotes: 2

Robert jardonneau
Robert jardonneau

Reputation: 444

Your onClick method is not bound to your class context, and therefore have no access to this.props.

The usual solution is to bind this method in your constructor :

constructor(props) {
  super(props);
  this.onClick = this.onClick.bind(this);
}

Another option is to bind in the render method as it's been suggested, however this means that the binding will be done at each render, instead of only one-time using the constructor solution.

Upvotes: 7

Related Questions