Event Handlers

What is an Event Handler?

Event Handlers are functions that can be triggered in response to a user interaction like clicking, hovering, focussing, or more.

Event handler functions are usually defined inside of your components and have names that start with handle, and then are followed by the name of the event.

Adding an Event Handler

How to add an Event Handler

  • Step 1: defining a function.

  • Step 2: pass it as a prop to whatever JSX flag is appropriate.

export default function Button() {
  return (
    <button>I don't do anything</button>
  )
}

Now, you want it to show a message that appears once the user clicks on it. There are a few simple steps you can take to achieve this goal:

  • Step 1: Declare a function called handleClick inside of the Button component.

  • Step 2: Implement the logic inside that function.

  • Step 3: Add an onClick={handleClick} to the <button> JSX.

export default function Button() {
  function handleClick() {
    alert('You clicked me!')
  }
  
  return (
    <button onClick={handleClick}>Click me</button>
  )
}

Reading Props in Event Handlers

Event handlers are declared inside of a component and can therefore access the components props. This means that if the component has a message prop, you can make the button event show that message once clicked using the handleClick.

Passing Event Handlers as Props

You can have the parent component specify a child's event handler.

This can be achieved by passing a prop that the component receives from its parent as the event handler.

In the example, this is a component named Toolbar, which renders PlayButton and UploadButton.

  • One: PlayButton passes handlePlayClick as the onClick prop to the Button inside.

  • Two: UploadButton passes () => alert('Uploading!) as the onClick prop to the Button inside.

And then, your Button also accepts the prop called onClick. This passes the prop directly to the <button> with the onClick={onClick}.

function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  )
}

function PlayButton({ movieName }) {
  function handlePlayClick() {
    alert(`Playing ${movieName}!`)
  }
  
  return (
    <Button onClick={handlePlayClick}>
      Play "{movieName}"
    </Button>
  )
}

export default function Toolbar() {
  return (
    <div>
      <PlayButton movieName="Delivery Service" />
      <UploadButton />
    </div>
  )
}

Naming Event Handler Props

<button> and <div> are built in components, and they only support browser event names like onClick.

But, when you build your own components, you can name their event handler props any way you like to.

So, when inside of a component, the example of the button we used previously, does not have to be called onClick but we could also have named that onSmash.

The <button> in lowercase still needs the onClick prop, but everywhere else, you could use onSmash.

Event Propagation

The cool thing about event handlers is that it will also catch events from any children your component might have. You can call this "bubbling" or "propagating" up the tree. Basically, this means that it starts where the event happened, and then goes up the tree.

Stopping Propagation

Quick Tip: the only argument an event handler receives is an event object. This is usually called e which stands for "event". This object can be used to read information about the event.

The event object mentioned above can also make you stop the propagation. You can do this when you want to prevent an event from reaching parent components. You can call e.stopPropagation().

Passing Handlers as alternatives to propagation

Example code:

function Button({ onClick, children }) {
  return (
    <button onCLick={e => {
      e.stopPropagation()
      onClick()
    }}>
    {children}
    </button>
  )
}

As you can see, the click handler only runs the onClick prop that is passed by the parent after the click handler runs a line of code.

You can add more code to this handler before calling the parent onClick. This is an alternative to propagation, since it lets the child component handle the event whilst the parent component can still specify additional behavior.

Preventing Default Behavior

Browsers can have default behavior associated with them. You can call e.preventDefault() on the event object to stop this from happening.

export default function Signup() {
  return (
    <form onSubmit={e => {e.preventDefault();alert('Submitting!');}}>
      <input />
      <button>Send</button>
    </form>
  )
}

A few notes

Functions that are passed to event handlers must actually be passed and not called.

// this is correct
<button onClick={handleClick}> </button>

// this is incorrect
<button onClick={handleClick()}> </button>