React Events

By

Learn how to handle events in React with camelCase props like onClick and onSubmit, passing a function and reading the synthetic event object.

~~~

React provides an easy way to manage events. Prepare to say goodbye to addEventListener.

In the previous article about state you saw this example:

const CurrencySwitcher = ({ currency, handleChangeCurrency }) => {
  return (
    <button onClick={handleChangeCurrency}>
      Current currency is {currency}. Change it!
    </button>
  )
}

If you’ve been using JavaScript for a while, this is just like plain old JavaScript event handlers, except that this time you’re defining everything in JavaScript, not in your HTML, and you’re passing a function, not a string.

The actual event names are a little bit different because in React you use camelCase for everything, so onclick becomes onClick, onsubmit becomes onSubmit.

For reference, this is old school HTML with JavaScript events mixed in:

<button onclick="handleChangeCurrency()">...</button>

Event handlers in function components

In a function component, a handler is a plain function you define inside the component. You can give it a name or write it inline. This is how you write React today, and the code below runs on React 19:

import { useState } from 'react'

const Converter = () => {
  const [currency, setCurrency] = useState('€')

  const handleChangeCurrency = () => {
    setCurrency(prev => (prev === '€' ? '$' : '€'))
  }

  return (
    <button onClick={handleChangeCurrency}>
      Current currency is {currency}. Change it!
    </button>
  )
}

Or pass an inline arrow when the logic is short:

<button onClick={() => setCurrency(prev => (prev === '€' ? '$' : '€'))}>
  Change currency
</button>

All handlers receive an event object that adheres, cross-browser, to the W3C UI Events spec. React wraps the native event (you’ll see it called a synthetic event) so the API is the same in every browser, and the original is available as event.nativeEvent. Call event.preventDefault() when you need to stop the browser’s default action, for example on form submit.

Old React tutorials tell you to call event.persist() before reading the event asynchronously. Event pooling was removed in React 17, so you can drop that call. The event object stays valid.

There is no this to bind in function components. The handler is a closure, so it already sees the state values and setters defined in the component body. More on state updates in the useState guide.

Class components and binding (legacy)

If you maintain older class components you’ll find handlers defined as methods. ES6 class methods are not bound by default, so this is undefined inside them unless you fix that.

Arrow class fields keep this pointing at the instance:

class Converter extends React.Component {
  handleClick = e => {
    /* ... */
  }
}

Or bind in the constructor:

class Converter extends React.Component {
  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }
  handleClick(e) {}
}

The events reference

There are lots of events supported, here’s a summary list.

Clipboard

Composition

Keyboard

Focus

Form

Mouse

Selection

Touch

UI

Mouse Wheel

Media

Image

Animation

Transition

Tagged: React · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about react: