Abstracting Button Events in React

While building my React & Redux project, I thought about how I can streamline how many functions and components I was using. An example being the game buttons.

“Start Game”, “Food” and “Foe” gameplay buttons

All buttons took in text as a prop and would need to fire off an action when clicked. If this was built without React, each button would need an event listener, then that event listener would fire off an action. For example.

this.submitButton.addEventListener('click', (e) => {
      this.createGame(e);
    });

You could blend multiple actions into one function based on the event that is passed in.

For example, in this function, an “Instructions” section is opened or closed, depending on if it is set to display:block or display:none.

this.instructions.addEventListener('click', (e) => {
     if (this.instructions.style.display == "none") {
       this.instructions.style.display = "block"
     } else {
       this.instructions.style.display = "none"
     }
   });

With that in mind, I could do something similar with my React Button components.

Building the Button

To start, my Button component looked like this:

<button onClick={this.handleClick}>
  {this.props.text} // this.props.text = "Start Game", "Food" or "Foe"
</button>

Which when clicked, would fire a function handleClick function.

handleClick = (e) => {
  this.props.startGame(); // This could be anything
}

I could create a handleStartGame function, a handleFood, etc, I could simply everything into one function, then fire off specific tasks based on the event (the button) that was clicked.

Abstracting onClick

First, I needed to 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 = "Start Game", "Food" or "Foe"
</button>

To this:

<button onClick={(e) => this.handleClick(e)}>
  {this.props.text} // this.props.text = "Start Game", "Food" or "Foe"
</button>

Now, the handleClick function can take in the event object. There are no id on the buttons, but the text is unique, we can use that as an identifier.

Switch Case for Event Target

Instead of an if/else statement, we can do a switch case that looks at the innerText of the event, and based on that, will fire a specific action.

For example, when the “Start Game’ button is clicked, we want to change the activeGame attribute in the Redux store to true. If the “Food” or “Foe” buttons are clicked, I want it to compare the guess, to the current emoji and return true if the guess is correct or false if it is not.

So let’s work through what’s happening.

switch (e.target.innerText) {
  case "Start Game":
    this.props.startGame();
    break;
  case "Food":
    console.log("The food button was clicked");
    this.props.guess(e.target.innerText);
    break;
  case "Foe":
    console.log("The foe button was clicked");
    this.props.guess(e.target.innerText);
    break;
  default:
    return
}

If the “Start Game” button is clicked, an event object is passed to the function. And the target property of that event object looks like this.

<button>Start Game</button>

From there, we can get to the innerText which has a value of “Start Game”. Since that meets the first switch case, the startGame function is fired. If the “Food” button was clicked, the second case is fired, and so one. 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, does not return an action and simply exits the function.

With this setup, I can change what each case does, or add new ones without having to change the functionality of the buttons themselves.

Leave a comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.