Abstracting Click Events in React
An essential part of programming is having clean and simplified code.
A function should do one thing, like update a follower count or submit a form, as opposed to multiple things at once. At the same time, if a function can be reused to perform similar actions based on what input or arguments it receives, it should do that.
As an example, let's say we have three buttons: "Pizza", "Cheeseburger" and "Ice Cream". We're feeling snackish, so let's assume that clicking a button, starts the order for that item.
If each Button
was a component in React, the return statement of that component may look like this:
<button onClick={this.handleClick}>
{this.props.text} // this.props.text = "Pizza", "Cheeseburger" or "Ice Cream"
</button>
Which when a button is clicked, it runs a handleClick
function.
handleClick = () => {
this.props.orderFood(); // This could be anything
}
While I could give each Button
instance it's own handleClick
function—handlePizzaOrder
, handleCheeseBurgerOrder
and handleIceCreamOrder
—that is creating a lot of work, for functions that do very similar things: Order an item.
What we can do, is take what we know about the Button
that was clicked and pass that information to a generalized or abstracted handleClick
function. Then, based on that information, run a specific order function.
Abstracting onClick
To start, my Button
component looked like this:
<button onClick={this.handleClick}>
{this.props.text} // this.props.text = "Pizza", "Cheeseburger" or "Ice Cream"
</button>
This means that when any of the three buttons are clicked, the handleClick
function starts running. At this point, the handleClick
function does not know which of the buttons was clicked. For this to happen, the handleClick
function needs to take in the event target.
To do that, we'll change the onClick
props to become an anonymous function that takes in the event.
The button goes from this:
<button onClick={this.handleClick}>
{this.props.text} // this.props.text = "Pizza", "Cheeseburger" or "Ice Cream"
</button>
To this:
<button onClick={(e) => this.handleClick(e)}>
{this.props.text} // this.props.text = "Pizza", "Cheeseburger" or "Ice Cream"
</button>
And the handleClick
function is updated to accept the event as an argument.
handleClick = (e) => {
// We'll update the rest of the function in the next step
}
Running a Function, Based on the Event Target
Instead of an if/else
statement, we can use a switch statement that looks at the innerText
of the event target, and based on that, will fire a specific function.
For example, when the "Pizza" button is clicked, we want to start the pizza ordering process of picking a size and toppings. For "Cheeseburger" a number of burger patties, how they should be cooked, and toppings.
Here's our handleClick
function and switch case:
handleClick = (e) => {
switch (e.target.innerText) {
case "Pizza":
this.props.orderPizza();
break;
case "Cheeseburger":
this.props.orderCheeseBurger();
break;
case "Ice Cream":
this.props.orderIceCream();
break;
default:
console.log("I'm sorry. We don't have that menu item.")
}
}
Now let's walk through what is happening.
If the “Pizza” button is clicked, an event object is passed to the function. It has a target
property that returns this.
<button>Pizza</button>
From there, we can get innerText
which has a value of “Pizza”. Since that meets the first switch case, the orderPizza
function is run. If the “Cheeseburger” button was clicked, the second case is fired, and so on.
If there was a fourth button that did not match any of the cases we have specified above, the default case is hit, which is our instance, prints a response to the console and exits the function.
Conclusion
With this setup, I can change what each switch case does, or add new ones without having to change the functionality of the buttons themselves. The return of the Button
component stays minimal which makes it easy to read and maintain.
This example is in the context of React, but the principle behind abstracting and keeping components small and easy to maintain can apply to other programming languages.