Handling Events

React events look like HTML events but are camelCased and take a function reference instead of a string. React uses synthetic events — a cross-browser wrapper around native browser events.

Basic Event Handlers

basic.jsx
import { useState } from 'react';

function ClickCounter() {
  const [count, setCount] = useState(0);

  // Define handler as a separate function
  function handleClick() {
    setCount(count + 1);
    console.log('Button clicked!');
  }

  return (
    <div>
      <p>Clicked {count} times</p>
      {/* Pass function reference, not a call */}
      <button onClick={handleClick}>Click me</button>

      {/* Or use inline arrow function */}
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  );
}

The Event Object

Every event handler receives a synthetic event object with useful properties:

event-object.jsx
function InputLogger() {
  function handleChange(e) {
    console.log(e.target.value);   // current input value
    console.log(e.target.name);    // input's name attribute
    console.log(e.type);           // "change"
    console.log(e.target.checked); // for checkboxes
  }

  function handleKeyDown(e) {
    if (e.key === 'Enter') {
      console.log('Enter pressed!');
    }
    if (e.ctrlKey && e.key === 's') {
      e.preventDefault();
      console.log('Ctrl+S intercepted');
    }
  }

  return (
    <input
      name="search"
      onChange={handleChange}
      onKeyDown={handleKeyDown}
      placeholder="Type something..."
    />
  );
}

Passing Arguments

To pass extra arguments to an event handler, wrap it in an arrow function:

arguments.jsx
function TodoList() {
  const todos = ['Buy milk', 'Write code', 'Sleep'];

  function handleDelete(index) {
    console.log(`Deleting todo at index ${index}`);
  }

  function handleEdit(todo, index) {
    console.log(`Editing "${todo}" at index ${index}`);
  }

  return (
    <ul>
      {todos.map((todo, i) => (
        <li key={i}>
          {todo}
          {/* Wrap in arrow function to pass arguments */}
          <button onClick={() => handleDelete(i)}>Delete</button>
          <button onClick={() => handleEdit(todo, i)}>Edit</button>
        </li>
      ))}
    </ul>
  );
}

Common Event Types

event-types.jsx
function EventExamples() {
  return (
    <div>
      {/* Mouse events */}
      <button onClick={() => console.log('clicked')}>Click</button>
      <button onDoubleClick={() => console.log('double!')}>Double-click</button>
      <div onMouseEnter={() => console.log('hover in')}
           onMouseLeave={() => console.log('hover out')}>
        Hover me
      </div>

      {/* Keyboard events */}
      <input onKeyDown={e => console.log('key down:', e.key)}
             onKeyUp={e => console.log('key up:', e.key)} />

      {/* Form events */}
      <input onChange={e => console.log('value:', e.target.value)} />
      <select onChange={e => console.log('selected:', e.target.value)}>
        <option value="a">Option A</option>
        <option value="b">Option B</option>
      </select>

      {/* Focus events */}
      <input onFocus={() => console.log('focused')}
             onBlur={() => console.log('blurred')} />
    </div>
  );
}
{{callout:warning:Don't call the function — pass the function. onClick={handleClick} is correct. onClick={handleClick()} calls it immediately on render!}}

Preventing Default Behavior

For links and forms, call e.preventDefault() to stop the browser's default action:

prevent-default.jsx
function LoginForm() {
  function handleSubmit(e) {
    e.preventDefault(); // Stops page reload
    const form = e.target;
    const email = form.email.value;
    const password = form.password.value;
    console.log('Logging in:', email);
    // Now call your API...
  }

  function handleLinkClick(e) {
    e.preventDefault(); // Stops navigation
    console.log('Link clicked but page did not navigate');
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" />
      <input name="password" type="password" />
      <button type="submit">Login</button>
      <a href="/signup" onClick={handleLinkClick}>Sign up</a>
    </form>
  );
}