Easy Tutorial
❮ Home React Rendering Elements ❯

React Event Handling

Event handling in React elements is similar to that in DOM elements. However, there are some syntactic differences:

The typical HTML way is:

<button onclick="activateLasers()">
  Activate Button
</button>

In React, it is written as:

&lt;button onClick={activateLasers}>
  Activate Button
</button>

Another difference in React is that you cannot prevent default behavior by returning false. You must explicitly use preventDefault.

For example:

<a href="#" onclick="console.log('Link clicked'); return false">
  Click me
</a>

In React, it is written as:

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('Link clicked');
  }

  return (
    &lt;a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

In the example, e is a synthetic event.

When using React, you usually do not need to use addEventListener to add a listener to a created DOM element. You simply need to provide a listener when the element is initially rendered.

When you use ES6 class syntax to define a component, event handlers become methods of the class. For example, the following Toggle component renders a button that allows the user to toggle a switch:

Example

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // Binding here is necessary so that `this` can be used in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      &lt;button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('example')
);

You must be careful with this in JSX callback functions. Class methods do not automatically bind this. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is called.

This is not specific to React; it is part of how functions work in JavaScript. Generally, if you do not append () to a method, such as onClick={this.handleClick}, you should bind this to the method.

If binding bothers you, there are two ways to solve it. If you are using experimental property initializer syntax, you can use property initializers to correctly bind callback functions:

class LoggingButton extends React.Component {
  // This syntax ensures that `this` is bound within handleClick
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      &lt;button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

If you are not using property initializer syntax, you can use arrow functions in the callback:

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    return (
      &lt;button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}

This syntax ensures that this is bound within handleClick.

return (
  &lt;button onClick={(e) => this.handleClick(e)}>
    Click me
  </button>
);
}
}

Using this syntax has a drawback: a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax to avoid such performance issues.


Passing Arguments to Event Handlers

It is common to pass extra parameters to event handlers. For example, if id is the ID of the row you want to delete, either of the following approaches will work:

&lt;button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
&lt;button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

In both examples, the event object e will be passed as the second argument. With the arrow function, we have to pass it explicitly, but with bind any further arguments are automatically forwarded.

It's important to note that when using bind, the event object e should be placed after the parameters in the listener function defined in the class component, for example:

class Popper extends React.Component {
  constructor() {
    super();
    this.state = { name: 'Hello world!' };
  }

  preventPop(name, e) { // The event object e should be placed last
    e.preventDefault();
    alert(name);
  }

  render() {
    return (
      <div>
        <p>hello</p>
        {/* Passing parameters via bind() method */}
        &lt;a href="https://reactjs.org" onClick={this.preventPop.bind(this, this.state.name)}>Click</a>
      </div>
    );
  }
}
❮ Home React Rendering Elements ❯