Event Handlers in React

How to determine what action will be taken whenever an Event is fired

Isha Jauhari
Jan 24 · 5 min read

Working of React Event handlers is very similar to how handling of events works on DOM elements. There are few differences though.

  • camelCase vs lowercase — onClick instead of onclick.
    We write React event handlers inside curly braces.
  • In case of React(/JSX), rather than passing a string, we pass a function as the event handler. onClick={buttonClicked} instead of onclick=”buttonClicked()”
// React
<button onClick={buttonClicked}>Click the Button!</button>
// HTML
<button onclick=”buttonClicked()”>Click the Button!</button>
  • Another difference is that in order to prevent default behavior in React, we cannot return false. We have to call preventDefault explicitly.
// HTML
<button onclick="console.log('Button clicked.'); return false">
Click Me
</button>
// React
function handleClick(e) {
e.preventDefault();
console.log('Button clicked.');
}
return (
<button onClick={handleClick}>
Click me
</a>
);

The Event Argument :

If you haven’t written too many event handlers before… don’t worry about remembering the differences! You’ll start to remember the different ‘e’ APIs as you use them.

Event Handler Bindings

So in case of regular functions, ‘this’ keyword represents the object that called the method. That calling object can be anything like global window object, a HTML button, or anything else. Hence ‘this’ keyword SHOULD represent the component that owns the method.

Now coming back to bindings. We have three way of binding event handlers.

1. Dynamic Binding :

class Button extends React.Component {
buttonClicked() {
alert("Button Clicked!");
}
render() {
return (
<p>{this.state.name}!</p>
<button onClick={this.buttonClicked.bind(this)}>Click the Button!</button>
);
}
}
ReactDOM.render(<Button />, document.getElementById('root'));

This approach will work, however the issue with this approach is that any changes in ‘this.state.name’ will result in re-rendering the component again.

This in turns again call ‘this.buttonClicked.bind(this)’ to bind the handler. As a result, new handler will be generated which will be completely different than the handler used when render() was called the first time.

If there are only few buttons on the page, this is somewhat OK, however this will be a mess if multiple buttons or event handlers are there.

2. Constructor Binding :

class Button extends React.Component {
constructor(props) {
super(props);
this.buttonClicked = this.buttonClicked.bind(this);
}
buttonClicked() {
alert(this);
/*
Due to binding in the constructor function,
the 'this' keyword now refers to the component object
*/
}
render() {
return (
<p>{this.state.name}!</p>
<button onClick={this.buttonClicked}>Click the Button!</button>
);
}
}
ReactDOM.render(<Button />, document.getElementById('root'));

In this approach, Calling render() again will not generate a new handler for onClick(). However the issue is, it can get tedious easily.

Since in this approach we need to use constructor, super(), and bind() for every single handler, it will eventually ends up being a lot of repetitive code.
To solve this problem, Arrow functions comes to rescue.

3. Using Arrow Function

class Button extends React.Component {
buttonClicked = () => {
alert(this);
/*
The 'this' keyword refers to the component object
*/
}
render() {
return (
<p>{this.state.name}!</p>
<button onClick={this.buttonClicked}>Click the Button! </button>
);
}
}
ReactDOM.render(<Button />, document.getElementById('root'));

In the above code, buttonClicked is an assignment which is equivalent to:
constructor() { this.buttonClicked = () => { … };}

Hence, once the component is initialized, this.buttonClicked will never change again. In this way, we can ensures that re-rendering of ‘<button>’ will not happen.

Passing Arguments

Basically arguments is the information that we give to a function or event handler to act upon.

We can do this in two way -

Using Anonymous Arrow function

class Button extends React.Component {
buttonClicked = (a) => {
alert(a);
}
render() {
return (
<button onClick={() => this.buttonClicked("Button Clicked", e)}>Click the Button!</button>
);
}
}
ReactDOM.render(<Button />, document.getElementById('root'));

Binding Event Handler to ‘this’ :

class Button extends React.Component {
buttonClicked(a) {
alert(a);
}
render() {
return (
<button onClick={this.buttonClicked.bind(this, "Button Clicked")}>Click the Button!</button>
);
}
}
ReactDOM.render(<Button />, document.getElementById('root'));

In above example, rather than using this.buttonClicked.bind(this, “Button Clicked”), if we use this.buttonClicked(this, “Button Clicked”), the buttonClicked function will be executed when the page is loaded. It will not wait for the button to actually clicked upon.

In both the cases, the React Event argument — ‘e’ will be passed as a second argument after the value. In case of arrow function, we have to pass it explicitly, however with bind() any further arguments are automatically forwarded.

I am not discussing about React Event Object and other things here for the sake of time. I will try to include all these topics in next article.

Conclusion

Regarding bindings, it is always good to go with “Arrow Function binding” whenever possible. In case of dynamic binding, we SHOULD consider below things before going ahead with it.

  • Appearance of affected component or components
  • Component State changing frequently or not

If Component or its state is changing frequently or there are many event handlers on the page, I prefer using “Handlers Caching” to deal with Performance Issue.

JavaScript in Plain English

Learn the web's most important programming language.

Isha Jauhari

Written by

Trying to learn new things every day and sharing my knowledge with people || Avid Reader

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade