Handling Events

Responding to user interactions in React

Event Handling in React

React events are similar to DOM events, but with a few key differences. They use camelCase naming (onClick instead of onclick) and you pass functions as event handlers, not strings.

React vs DOM Events

HTML/DOM

<button onclick="handleClick()">

React

<button onClick={handleClick}>

Basic Event Handling

function Button() {
  // Define the event handler function
  const handleClick = () => {
    alert('Button was clicked!');
  };

  // Pass the function reference (not a function call!)
  return <button onClick={handleClick}>Click Me</button>;
}

// Inline handler (for simple cases)
function InlineExample() {
  return (
    <button onClick={() => alert('Clicked!')}>
      Click Me
    </button>
  );
}

⚠️ Common Mistake

Pass the function, don't call it: onClick={handleClick}
Not: onClick={handleClick()} ✗ (this calls it immediately!)

The Event Object

Event handlers receive a synthetic event object with properties similar to native DOM events:

function Form() {
  const handleSubmit = (event) => {
    event.preventDefault();  // Prevent form submission
    console.log('Form submitted!');
  };

  const handleChange = (event) => {
    console.log('Input value:', event.target.value);
    console.log('Input name:', event.target.name);
  };

  const handleKeyDown = (event) => {
    if (event.key === 'Enter') {
      console.log('Enter pressed!');
    }
    console.log('Key:', event.key);
    console.log('Ctrl held:', event.ctrlKey);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        name="email"
        onChange={handleChange}
        onKeyDown={handleKeyDown}
      />
      <button type="submit">Submit</button>
    </form>
  );
}

Common Events

Category Events
Mouse onClick, onDoubleClick, onMouseEnter, onMouseLeave, onMouseMove
Keyboard onKeyDown, onKeyUp, onKeyPress
Form onChange, onSubmit, onFocus, onBlur
Touch onTouchStart, onTouchMove, onTouchEnd
Scroll onScroll
Clipboard onCopy, onCut, onPaste

Passing Arguments to Event Handlers

function ItemList() {
  const items = ['Apple', 'Banana', 'Cherry'];

  // Method 1: Arrow function wrapper
  const handleDelete = (itemName) => {
    console.log('Deleting:', itemName);
  };

  // Method 2: With event object
  const handleClick = (id, event) => {
    console.log('Clicked item:', id);
    console.log('Event:', event);
  };

  return (
    <ul>
      {items.map((item, index) => (
        <li key={item}>
          {item}
          {/* Arrow function to pass argument */}
          <button onClick={() => handleDelete(item)}>
            Delete
          </button>
          {/* Passing both id and event */}
          <button onClick={(e) => handleClick(index, e)}>
            Click
          </button>
        </li>
      ))}
    </ul>
  );
}

Events with State

import { useState } from 'react';

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

  const increment = () => setCount(prev => prev + 1);
  const decrement = () => setCount(prev => prev - 1);
  const reset = () => setCount(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={decrement}>-</button>
      <button onClick={increment}>+</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

function ToggleSwitch() {
  const [isOn, setIsOn] = useState(false);

  const toggle = () => setIsOn(prev => !prev);

  return (
    <button 
      onClick={toggle}
      style={{ background: isOn ? 'green' : 'gray' }}
    >
      {isOn ? 'ON' : 'OFF'}
    </button>
  );
}

Event Handler Naming Conventions

// Convention: handle + Event/Action
function MyComponent() {
  // For the handler function
  const handleClick = () => { };
  const handleSubmit = () => { };
  const handleUserDelete = () => { };
  const handleInputChange = () => { };

  // For props that accept handlers
  // Convention: on + Event/Action
  return (
    <ChildComponent 
      onClick={handleClick}
      onSubmit={handleSubmit}
      onUserDelete={handleUserDelete}
    />
  );
}

// Child component receives with "on" prefix
function ChildComponent({ onClick, onSubmit, onUserDelete }) {
  return (
    <button onClick={onClick}>Click</button>
  );
}

Preventing Default Behavior

function Form() {
  // Prevent form submission reload
  const handleSubmit = (e) => {
    e.preventDefault();
    // Handle form data...
  };

  return <form onSubmit={handleSubmit}>...</form>;
}

function Link() {
  // Prevent link navigation
  const handleClick = (e) => {
    e.preventDefault();
    console.log('Link clicked, but navigation prevented');
  };

  return <a href="/page" onClick={handleClick}>Click Me</a>;
}

Event Propagation

function Parent() {
  const handleParentClick = () => {
    console.log('Parent clicked');
  };

  const handleChildClick = (e) => {
    e.stopPropagation();  // Stop event from bubbling up
    console.log('Child clicked');
  };

  return (
    <div onClick={handleParentClick} style={{ padding: '20px', background: '#eee' }}>
      Parent
      <button onClick={handleChildClick}>
        Child (won't trigger parent)
      </button>
    </div>
  );
}

// Capture phase (rarely used)
function CaptureExample() {
  return (
    <div onClickCapture={() => console.log('Captured!')}>
      <button onClick={() => console.log('Clicked!')}>
        Button
      </button>
    </div>
  );
}

Hover and Focus Events

function InteractiveCard() {
  const [isHovered, setIsHovered] = useState(false);
  const [isFocused, setIsFocused] = useState(false);

  return (
    <div
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
      style={{ 
        background: isHovered ? '#f0f0f0' : 'white',
        transform: isHovered ? 'scale(1.02)' : 'scale(1)'
      }}
    >
      <input
        onFocus={() => setIsFocused(true)}
        onBlur={() => setIsFocused(false)}
        style={{ 
          borderColor: isFocused ? 'blue' : 'gray' 
        }}
      />
    </div>
  );
}

🎯 Event Handling Best Practices

  • ✓ Use camelCase for event names (onClick, onChange)
  • ✓ Pass functions, don't call them
  • ✓ Use meaningful handler names (handleClick, handleSubmit)
  • ✓ Extract complex handlers into named functions
  • ✓ Use e.preventDefault() for forms and links when needed
  • ✓ Use e.stopPropagation() to prevent event bubbling
  • ✓ Keep handlers close to where they're used