tezvyn:

React's SyntheticEvent: One Wrapper for All Browsers

AI-drafted, machine-checkedSource: react.devintermediate
React's SyntheticEvent: One Wrapper for All Browsers

React's SyntheticEvent is a browser-agnostic wrapper around native events, ensuring your `onClick` handlers behave identically everywhere. The main footgun: event objects are pooled for performance, so you can't access their properties in an async callback.

WHY IT EXISTS Browsers have minor but frustrating inconsistencies in their event system implementations. For example, property names might differ between browsers for the same event. React abstracts away these differences to provide a stable, cross-browser API for developers.

THE MENTAL MODEL Think of SyntheticEvent as a diplomatic translator. A native browser event speaks a specific dialect (e.g., an old Safari click event). The SyntheticEvent translator takes that dialect and converts it into a universal language that your React component understands, guaranteeing properties like e.target and e.preventDefault() work the same everywhere.

HOW IT WORKS React uses event delegation. Instead of attaching a listener to every DOM node with an onClick, it attaches a single listener for each event type at the document root. When an event fires, React's listener identifies the component, creates or retrieves a pooled SyntheticEvent object that wraps the native event, and then calls your handler. After your handler executes, the SyntheticEvent object is released back to a pool to be reused, which improves performance by reducing garbage collection.

WHEN TO USE IT You use it implicitly every time you write an event handler in React, like onKeyDown, onFocus, or onClick. The first argument your handler function receives is always a SyntheticEvent instance.

WHEN NOT TO USE IT If you need the raw browser event, perhaps for a third-party library that expects it, you can access it via the nativeEvent property on the synthetic event object (e.g., e.nativeEvent). This is an escape hatch and rarely needed.

ONE CANONICAL EXAMPLE The most common footgun is accessing an event asynchronously. Consider function handleChange(e) { setTimeout(() => { console.log(e.target.value); }, 100); }. This will fail because by the time the timeout runs, the event e has been recycled. To fix this, either extract the data you need before the async call (const value = e.target.value;) or call e.persist() to tell React not to recycle that specific event object.

Read the original → react.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.