Lesson 1.5

Mastering Events

Building interactive applications requires one fundamental capability: responding to user actions. Clicks, keyboard presses, text input, copying, dragging — modern interfaces depend on events.

What you'll learn
  • How event handlers work in React
  • The difference between function references and invocations
  • Why event handlers belong inside components
  • How to access event information
  • Building interactive applications with events

React's event system makes this straightforward, but fully understanding how handlers work, how they are passed, and how React invokes them will make you a far more confident developer.

Event Handlers Start as Simple Functions

Imagine we want a button that logs a message when clicked. Start with the UI:

jsx
export default function LoggerButton() {
  return <button>Log Something</button>
}

Now create the event handler:

javascript
const handleClick = () => {
  console.log("Button clicked")
}

And wire it together via React's built-in onClick prop:

jsx
export default function LoggerButton() {
  const handleClick = () => {
    console.log("Button clicked")
  }

  return <button onClick={handleClick}>Log Something</button>
}

This example demonstrates two universal patterns:

  • You encapsulate logic into dedicated event handler functions
  • You pass a function reference, not a result

Reference vs. Invocation: The Most Common Beginner Mistake

These look similar but behave very differently:

jsx
<button onClick={handleClick}>Reference</button>
<button onClick={handleClick()}>Invocation</button>
  • Passing a reference (handleClick) → React can call it later
  • Passing an invocation (handleClick()) → JavaScript calls it immediately and passes the returned value to onClick

Most of the time, the invocation version breaks your UI because React receives something like undefined instead of a function.

This applies to all props that expect functions, not just event handlers.

Why Event Handlers Live Inside Components

Here's a small button that shows an alert based on a prop:

jsx
function AlertButton({ text }) {
  const handleClick = () => alert(text)

  return <button onClick={handleClick}>Show Alert</button>
}

Because the handler is defined inside the component, it automatically receives access to props, state, and anything else in scope.

If we move the handler outside:

jsx
function handleClick() {
  alert(text) // ❌ ReferenceError
}

function AlertButton({ text }) {
  return <button onClick={handleClick}>Show Alert</button>
}

You lose access to text. React devs quickly learn that event handlers belong inside components unless there is a very explicit performance reason not to.

"But React Rerenders — Doesn't It Recreate Functions?"

Yes. And it's usually irrelevant.

JavaScript engines are extremely optimized at allocating and freeing functions. A typical React render creates dozens of them; this is normal and expected.

Only in extremely heavy interaction scenarios do you start worrying about stable references — but then you use useCallback or memoization, which belongs in an advanced topic.

Accessing Event Information

Every React event handler receives a Synthetic Event — React's cross-browser wrapper around native browser events.

For example:

javascript
function handleChange(e) {
  console.log(e.target.value)
  console.log(e.timeStamp)
}

Useful properties include:

  • targetthe element that triggered the event
  • currentTargetthe element the handler is bound to
  • timeStampwhen the event occurred
  • typethe type of event, e.g., "click"

Let's build something practical that relies on event data.

A Real Example: Build a "Fast Typer" Mini-Game

Goal:

Show the user a random word. They must type it and press Enter within 3 seconds.

Step 1: Utilities and UI

javascript
const WORDS = ["react", "javascript", "hooks", "state", "props"]

function getRandomWord() {
  return WORDS[Math.floor(Math.random() * WORDS.length)]
}

Component skeleton:

jsx
export default function FastTyper() {
  const [word, setWord] = React.useState(() => getRandomWord())
  const [startTime, setStartTime] = React.useState(() => Date.now())

  return (
    <div>
      <h2>Type this word:</h2>
      <strong>{word}</strong>
      <input placeholder="Start typing..." />
      <button>Reset</button>
    </div>
  )
}

Step 2: Handle Typing

We must know:

  • What the user typed (e.target.value)
  • When they typed it (Date.now())
javascript
function handleKeyDown(e) {
  if (e.key !== "Enter") return

  const elapsed = Date.now() - startTime
  const isCorrect = e.target.value.trim() === word
  if (!isCorrect) {
    alert("Incorrect word!")
  } else if (elapsed > 3000) {
    alert("Too slow!")
  } else {
    alert("Winner!")
  }
}

Attach the handler:

jsx
<input onKeyDown={handleKeyDown} placeholder="Start typing..." />

Step 3: Reset Handler

javascript
function handleReset() {
  setWord(getRandomWord())
  setStartTime(Date.now())
}

Final JSX:

jsx
<button onClick={handleReset}>Reset</button>

This example demonstrates:

  • Passing event handlers
  • Reading event data
  • Comparing timestamps
  • Binding handlers in JSX

Full Component for Reference

jsx
const WORDS = ["react", "javascript", "hooks", "state", "props"]
const getRandomWord = () => WORDS[Math.floor(Math.random() * WORDS.length)]

export default function FastTyper() {
  const [word, setWord] = React.useState(() => getRandomWord())
  const [startTime, setStartTime] = React.useState(() => Date.now())

  const handleKeyDown = (e) => {
    if (e.key !== "Enter") return
    
    const elapsed = Date.now() - startTime
    const isCorrect = e.target.value.trim() === word
    if (!isCorrect) return alert("Incorrect word!")
    if (elapsed > 3000) return alert("Too slow!")
    alert("Winner!")
  }

  const handleReset = () => {
    setWord(getRandomWord())
    setStartTime(Date.now())
  }

  return (
    <div>
      <h2>Type this word:</h2>
      <strong>{word}</strong>
      <input
        autoFocus
        placeholder="Start typing…"
        onKeyDown={handleKeyDown}
      />
      <button onClick={handleReset}>Reset</button>
    </div>
  )
}

All React Events at Your Disposal

React supports a wide range of events:

(click, copy, drag, keydown, blur, submit, wheel, touchstart, animationend, etc.)

Rather than listing them again here, remember the rule:

If the browser supports it, React probably supports it too — with camelCase naming

Summary

Events are at the heart of interactive UI development. Once you understand:

  • passing references
  • placing handlers inside components
  • leveraging lexical scope
  • and using the Synthetic Event object

…you can implement anything from simple button clicks to full-blown interactive games and applications.