DEV Community

Alok Kumar
Alok Kumar

Posted on • Updated on

React Events

Hello Everyone πŸ‘‹πŸ‘‹πŸ‘‹

In this blog, we are going to talk about React Events, How to attach event handlers to components in React, this keyword, the problem with this keyword, How to solve that problem and much more.


So let's talk about Events, just like in HTML we can also handle user events in React and perform some actions based on them.

Just there are few changes in how we use them-

  • In React, events are written in camelCase :

onClick instead of onclick

  • Also In JSX you can pass function as an event handler rather than a string as in HTML :

onClick={generate} instead of onclick="generate()"


Using special reserved attributes we can attach event handlers to HTML elements in React.

Let's have a look at some examples of Event Attributes :

  • Mouse events : onClick, onMouseOver, etc
  • Form events : onSubmit, etc
  • Keyboard events: onKeyUp, onKeyDown, etc

Have a look at the whole list of supported events.


An example of how to use event handlers :

class Bakery extends React.Component {
  bake() {
    alert("The Cake is Baked!");
  }

  render() {
    return (
      <button onClick={this.bake}>Bake the Cake!</button>
    );
  }
}

ReactDOM.render(<Bakery />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

We use event handlers independently like for alert or console.log, like in the above example, therefore, we have not used keyword this till now but when we have to set state, access prop or just to access the state, etc then we have to reference keyword this like this.setState or this.props and many more.

But when we use keyword this inside a method we will lose the this context.

And the keyword this used inside the methods will return undefined and will generate an error :

class Bakery extends React.Component {
  constructor(props){
    super(props);
  }

  bake() {
    console.log(this); // 'this' is undefined
  }

  render() {
    return (
      <button onClick={this.bake}>Bake the Cake!</button>
    );
  }
}

ReactDOM.render(<Bakery />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode



We have to make sure that the keyword this refers to the component itself, the individual instance of the component.

For this, we have to have to bind this to the component instance.


Ways to bind this -

  • Use bind inline :
class Bakery extends React.Component {
  constructor(props){
    super(props);
  }

  bake() {
    console.log(this); // "this" refers to the component object
  }

  render() {
    return (
      <button onClick={this.bake.bind(this)}>Bake the Cake!</button> // binding inline
    );
  }
}

ReactDOM.render(<Bakery />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode



The pros of using binding inline is that it is super easy to use but it has some cons which are if we need to pass it to multiple components we have to bind it multiple times and on every render a new function is created.

So, we have a better way of binding this but before that let's have a look on a way through which we can bind this without the use of the word bind -

  • Using arrow function :
class Bakery extends React.Component {
  constructor(props){
    super(props);
  }

  bake() {
    console.log(this); // "this" refers to the component object
  }

  render() {
    return (
      <button onClick={() => this.bake()}>Bake the Cake!</button> // binding using arrow function
    );
  }
}

ReactDOM.render(<Bakery />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode



But this also comes with the same set of cons as inline binding so now let's finally look at the better approach -

  • Method binding in the constructor :
class Bakery extends React.Component {
  constructor(props) {
    super(props);
    this.bake = this.bake.bind(this); // binding in the constructor
  }

  bake() {
    console.log(this); // "this" refers to the component object
  }

  render() {
    return (
      <button onClick={this.bake}>Bake the Cake!</button>
    );
  }
}

ReactDOM.render(<Bakery />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode



The pros are that we only need to bind once, it is more performant and the cons is simply the lengthy syntax.

There are also some other ways to bind but I found this approach the most descriptive and efficient.


Till now we have seen simple event handlers which call a method but what if we want to pass some data? Let's look at how to bind with arguments.


Lets try and pass something like we usually do :

class Bakery extends React.Component {
  constructor(props) {
    super(props);
  }

  bake(e) {
    alert(e); // it will execute immediately
  }

  render() {
    const e = "Baked!";
    return <button onClick={this.bake(e)}>Bake the Cake!</button>;
  }
}

ReactDOM.render(<Bakery />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

But this will not work as we want. And the function will be executed immediately. So to solve this we have to bind it. There are a few ways for doing the same :

  • Binding the value of this using .bind :
class Bakery extends React.Component {
  constructor(props) {
    super(props);
  }

  bake(e) {
    alert(e); // it will execute after clicking the button
  }

  render() {
    const e = "Baked!";
    return <button onClick={this.bake.bind(this, e)}>Bake the Cake!</button>; // passing argument using .bind
  }
}

ReactDOM.render(<Bakery />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

Here firstly we will bind and then pass the data as the second argument. And it will work as we want, after clicking the button.

  • Using arrow function :
class Bakery extends React.Component {
  constructor(props) {
    super(props);
  }

  bake(e) {
    alert(e); // it will execute after clicking the button
  }

  render() {
    const e = "Baked!";
    return <button onClick={() => this.bake(e)}>Bake the Cake!</button>; // passing argument using arrow function
  }
}

ReactDOM.render(<Bakery />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

And it will work fine too. But both the cases have a drawback as discussed earlier after each click they will create a new function.


To solve this we have an approach that I'll discuss in the next blog.


Thanks for reading πŸ™

Any feedback appreciated 😁

Say HI πŸ‘‹πŸ‘‹πŸ‘‹

Happy Coding πŸ’»

Top comments (0)