What are Synthetic Events in React?

This article provides a clear and concise overview of Synthetic Events in React, explaining what they are, why React uses them, and how they differ from native browser events. You will learn about the benefits of React’s event-handling system, including cross-browser compatibility and performance optimization, as well as how to work with them in your code.

Understanding Synthetic Events

A Synthetic Event is a cross-browser wrapper around the browser’s native event. It has the same interface as the browser’s native event, including methods like preventDefault() and stopPropagation(), but it is designed to behave identically across all modern browsers.

When you write an event handler in React, such as onClick or onChange, the event object passed to your function is not a native browser event. Instead, it is an instance of SyntheticEvent.

Why React Uses Synthetic Events

React implements this wrapper system for two primary reasons:

1. Cross-Browser Consistency

Different browsers historically handle events in slightly different ways, using different property names or behaviors. React’s Synthetic Events normalize these differences so that your event-handling code works seamlessly across Chrome, Firefox, Safari, Edge, and older browsers without requiring browser-specific workarounds.

2. Performance Optimization (Event Delegation)

Instead of attaching individual event listeners to every DOM node that needs one, React attaches a single event listener to the root of your document (or the root of the React tree in React 17+).

When an event fires in the browser, it bubbles up to this root listener. React then maps the native event to the appropriate SyntheticEvent and dispatches it to the correct React component. This process is called event delegation, and it drastically reduces memory consumption and improves application performance.

Key Differences Between Synthetic and Native Events

While Synthetic Events mimic native events, there are a few key differences to keep in mind:

Accessing the Native Event

If you ever need to access the underlying browser event for a specific API that React does not wrap, you can do so using the nativeEvent attribute:

const handleClick = (event) => {
  console.log(event); // This is the SyntheticEvent
  console.log(event.nativeEvent); // This is the actual native browser PointerEvent/MouseEvent
};

Note on Event Pooling (React 16 vs. React 17+)

In React 16 and earlier, React used a technique called Event Pooling to improve performance. Synthetic event objects were reused, and their properties were nullified immediately after the event callback ran. To access event properties asynchronously (e.g., inside a setTimeout), you had to call event.persist().

In React 17 and later, event pooling has been removed. You can now access event properties asynchronously without needing to call event.persist().