Event handlers

Event handlers

Hooray, you’ve arrived at the event handlers lesson! This means that you’re finally ready to make an app that actually does something. So to celebrate, let’s do a quick quiz.

What kind of value would you pass to a button element’s onClick prop?

You’d pass a function!

When the user interacts with a <button>, <input> or <textarea>, your app won’t know what to do unless you tell it what to do. And that’s where event handler functions come in: when you pass React an event handler function, it’ll call it in response to user clicks, key presses or other events.

In the JavaScript community, these handler functions are sometimes called callback functions, or callbacks for short. (But this is really just a fancy way of saying function.) For example, you could use a callback to complain about not really wanting to add a contact thank you very much.

index.js
import React from 'react'
import ReactDOM from 'react-dom'

ReactDOM.render(
  <button onClick={() => {
    window.alert(`
      Here I am with a brain the size of a planet,
      and they tell me to add a contact.
    `)
  }}>
    Add a contact
  </button>,
  document.getElementById('root')
)
Build In Progress

Simple, huh? But why is the prop called onClick?

#Event props

React’s event props are named after DOM events from raw JavaScript. For example, the onClick prop from the above example is named after the DOM click event. If you’ve used jQuery or raw JavaScript before, React’s events will feel familiar.

React has props for most DOM events. For example:

  • onClick and onMouseMove can be used with any HTML element
  • onKeyDown and onFocus can be used with focusable elements
  • onSubmit can be used with <form> elements

You can see a complete list of events in React’s events documentation, or in the toolbox’s live events cheatsheet.

There is one important exception: the onChange prop. While the DOM change event is only fired after an input loses focus, React’s onChange prop is called immediately after each change; it acts like the DOM onInput event. And this is surprisngly handy for making controlled inputs actually work.

#Event objects

Whenever React calls an event callback, it passes a single argument that holds the nitty gritty: the event object.

But what is the nitty gritty? The answer depends on the type of event! For example:

  • Keyboard events will have a key property that specifies the key that was pressed
  • Mouse events will hold clientX and clientY properties that tell you where the mouse was at the time of the event
index.js
import React from 'react'
import ReactDOM from 'react-dom'

let left = undefined
let top = undefined

// The event object will be passed to your callback as its first argument.
// You can call it anything, but it doesn't hurt to stick with `event`.
function moveButton(event) {
  left = event.clientX + 2
  top = event.clientY + 2
  renderApp()
}

function renderApp() {
  ReactDOM.render(
    <button
      onMouseMove={moveButton}
      style={{ left, top, position: left ? 'fixed' : 'absolute' }}>
      Add a contact
    </button>,
    document.getElementById('root')
  )
}

renderApp()
Build In Progress

Just as React’s prop names mirror their DOM cousins, React’s event objects follow the structure of the DOM event objects wherever possible. In fact, the two most commonly used properties are identical:

  • preventDefault(), a method that will cancel the browser’s default behavior for the event (often used for preventing form submission)
  • target, which holds the DOM node where the event originated

Of course, even if you do know about DOM events, it’s easy to forget the exact names and object structures. I forget all the time. And that’s why I recommend that you bookmark a good source of documentation when working with events, like the toolbox’s live events cheatsheet.

#It’s time to capture some keystrokes.

Now that you know the fundamentals of events and event objects, I have a quick exercise for you.

Your task is to use an onChange prop to log keystrokes in the below input field to the console.

As a hint, the only piece of information that you’ll need from the event object is event.target.value.

index.js
import React from 'react'
import ReactDOM from 'react-dom'

ReactDOM.render(
  <input
    placeholder='Type something...'
    value=''
  />,
  document.getElementById('root')
)
Build In Progress

    Did you get it? If you get stuck, and you’ve given it a try, then feel free to check my solution.

    But there’s still one thing missing, even from my solution: the input is still read only. So how can we make a form that actually works?

    One possibility would be to re-render the control using ReactDOM.render(), as you did earlier with the fractal tree. But while this works at a small scale, imagine structuring an entire app this way. You’d need to recompute your top level App element’s props from each and every one of your app’s event handlers, each using some slightly different process. It would be a nightmare.

    Luckily, React provides a better way to manage input state — which we’ll take a look at right after another exercise.