React: Synthetic Events vs Native Events
When you attach an event listener in React (like onClick={(e) => console.log(e)}), the e object you receive is not the standard native browser event.
What is a Synthetic Event in React, and why does React use them instead of Native DOM events?
1. What is a Synthetic Event?
A Synthetic Event is a cross-browser wrapper created by React that encapsulates the native browser event.
It implements the exact same interface as the native event (meaning methods like e.stopPropagation() and e.preventDefault() work exactly as you expect), but it solves massive architectural problems under the hood.
To access the raw, underlying browser event, you can inspect e.nativeEvent.
function Button() {
const handleClick = (e) => {
console.log(e); // SyntheticEvent (React wrapper)
console.log(e.nativeEvent); // PointerEvent (Native browser event)
};
return <button onClick={handleClick}>Click Me</button>;
}2. Why does React use Synthetic Events?
A. Cross-Browser Normalization
Historically, different browsers (Chrome, Safari, Internet Explorer) implemented event behaviors differently. A mouse event in one browser might have different properties than in another. React's Synthetic Event normalizes all these inconsistencies. You can write your event handlers once, and React guarantees they will behave identically across all supported browsers.
B. Event Delegation (Performance)
If you render a list of 1,000 items and attach an onClick to every single item, attaching 1,000 distinct event listeners to the DOM would consume immense memory.
Instead, React utilizes Event Delegation.
React only attaches one single event listener at the very root of your document (or the React root container in React 17+). When a user clicks a nested button, the event bubbles up to the root. React intercepts it there, figures out which component the click belongs to, and dispatches a Synthetic Event directly to your onClick handler.
This makes React incredibly fast and memory-efficient.
3. Event Pooling (Legacy React 16 knowledge)
If you are dealing with legacy React code (v16 and below), you might encounter bizarre bugs when dealing with asynchronous code inside event handlers.
In React 16, to save memory, React re-used Synthetic Event objects. As soon as your onClick function finished running, React wiped all properties on the event object to null and put it back in a "pool" to be used by the next click.
If you tried to read e.target inside a setTimeout, the event would already be nullified, crashing your app! You had to call e.persist() to stop React from recycling it.
React 17 entirely removed Event Pooling. Modern React no longer recycles event objects, so they are perfectly safe to use inside asynchronous callbacks without calling persist().
Senior-Level Interview Answer
A Synthetic Event is React's cross-browser wrapper around the browser's native DOM event. Its primary purpose is to normalize event behavior across different browser engines, ensuring a consistent developer experience while preserving the standard W3C event interface. Architecturally, Synthetic Events power React's highly optimized Event Delegation system; rather than attaching physical event listeners to individual DOM nodes, React attaches a single global listener at the root container. This intercepts all bubbling events and maps them to the corresponding component handlers, drastically reducing memory overhead. While legacy versions of React utilized "Event Pooling" for garbage collection optimization—requiring
e.persist()for async access—this mechanic was removed in React 17 to improve developer ergonomics.
Common Interview Mistakes
❌ Misunderstanding Event Delegation bounds
In React 16, React attached the global event listener to the document object. This caused major conflicts if you had multiple React applications running on the same page (like micro-frontends). In React 17+, React attaches the delegated listener to the React Root container (div#root), gracefully solving these isolation conflicts. This is a great piece of trivia to impress an interviewer!
