Preventing double clicks in React

1/14/2019

Most of the time in React you will pass an onClick handler to a button, and whenever that button is click, expect that function to be called.

<button onClick={() => console.log("I was called")}>Click me</button>

This onClick will get called, every time the button is clicked. Sometimes this function might call an endpoint, and in some cases, you may not want that endpoint to run multiple times.

To get around this, you can use state to detect if the button was clicked, disable the button from being clicked further, then perform our action. The steps would be:

  1. Click the button
  2. Set the state of the component to track the button click
  3. Update the button (re-render) to disable it, and prevent further clicking
  4. Perform our action (using componentDidUpdate)
  5. Restore the button state, once the action is complete

Example:

Below is a custom component that handles doubleclicking of buttons. All of its props are passed down to the HTML button element, except the onClick handler, which we will wrap with our custom logic.

import React from "react";

class PreventDoubleClickButton extends React.component {
  constructor(props) {
    super(props);
    this.state = { clicked: false };

    this.onClick = this.onClick.bind(this);
  }

  onClick(event) {
    this.setState({ clicked: true });
  }

  componentDidUpdate(prevProps, prevState) {
    // If we previously weren't clicked, and then updated to be clicked, we want to run our click handler;
    if (!prevState.clicked && this.state.clicked) {
      // Here we expect the onClick function passed down, to return a Promise, once complete
      this.props.onClick().then(() => {
        this.setState({ clicked: true });
      });
    }
  }

  render() {
    return (
      <button {...this.props} onClick={this.onClick}>
        {this.props.children}
      </button>
    );
  }
}

// Usage

function handleClick() {
  return fetch("./myData.json").then(() => {
    this.setState({ data: "Got it!" });
  });
}

<PreventDoubleClickButton className="myButton" onClick={this.handleClick}>
  Click me
</PreventDoubleClickButton>;