SyntaxStudy
Sign Up
React Handling onClick and Synthetic Events
React Beginner 1 min read

Handling onClick and Synthetic Events

React wraps native browser events in a cross-browser compatible layer called SyntheticEvent. Synthetic events have the same interface as native events — `target`, `currentTarget`, `preventDefault()`, `stopPropagation()` — but React recycles the event object for performance reasons (in React 17 and earlier the object was nullified after the handler returned; React 17+ removed pooling). In practice you interact with React events exactly as you would with DOM events. Event handlers in JSX are camelCase (`onClick`, `onChange`, `onSubmit`, `onKeyDown`) and receive a function reference, not a function call. Writing `onClick={handleClick}` passes the function; `onClick={handleClick()}` calls it immediately during render, which is almost always a bug. When you need to pass additional arguments to a handler, wrap it in an arrow function: `onClick={() => handleDelete(item.id)}`. The `SyntheticEvent.preventDefault()` method prevents default browser behaviour — essential for custom form submission and link navigation. `stopPropagation()` halts event bubbling up the component tree. Unlike HTML event attributes that accept strings, JSX event handlers accept any JavaScript function, which means you can compose, memoize, and test them like any other function.
Example
import { useState } from 'react';

function EventDemo() {
  const [log, setLog] = useState([]);

  const addLog = (msg) => setLog(prev => [msg, ...prev].slice(0, 6));

  // Plain handler reference
  const handleClick = () => addLog('Button clicked');

  // Handler that reads event properties
  const handleMouseMove = (e) => {
    addLog(`Mouse at (${e.clientX}, ${e.clientY})`);
  };

  // Handler with an argument — wrap in arrow function
  const handleDelete = (id) => addLog(`Delete item #${id}`);

  // Prevent default form submission
  const handleSubmit = (e) => {
    e.preventDefault();
    addLog('Form submitted (default prevented)');
  };

  return (
    <div>
      <button onClick={handleClick}>Click me</button>

      <div
        style={{ width: 200, height: 60, background: '#f0f4f8', marginTop: 8 }}
        onMouseMove={handleMouseMove}
      >
        Move mouse here
      </div>

      <div style={{ marginTop: 8 }}>
        {[1, 2, 3].map(id => (
          <button key={id} onClick={() => handleDelete(id)}>
            Delete #{id}
          </button>
        ))}
      </div>

      <form onSubmit={handleSubmit} style={{ marginTop: 8 }}>
        <input type="text" placeholder="Type something" />
        <button type="submit">Submit</button>
      </form>

      <ul style={{ marginTop: 8 }}>
        {log.map((entry, i) => <li key={i}>{entry}</li>)}
      </ul>
    </div>
  );
}

export default EventDemo;