What is Event Pooling in React?
Event pooling was a performance optimization technique used in older versions of React (React 16 and earlier) to improve application speed by reusing event objects. This article explains how event pooling works, the common issues it caused for developers—particularly when dealing with asynchronous code—and why the React team ultimately decided to remove it in React 17.
Understanding the Concept of Event Pooling
In React, event handlers do not receive native browser events.
Instead, they receive instances of SyntheticEvent, which is
a cross-browser wrapper around the browser’s native event.
Historically, creating a new SyntheticEvent object for
every single user interaction put a strain on garbage collection,
especially in older web browsers. To solve this, React implemented event
pooling. Instead of destroying and recreating event objects constantly,
React kept a “pool” of event objects.
When an event was triggered, React would: 1. Retrieve an event object from the pool. 2. Populate its properties with the current event data. 3. Execute your event handler function. 4. Immediately clear (nullify) all properties on the event object. 5. Return the object to the pool for future reuse.
The Problem with Asynchronous Access
While event pooling was great for memory management, it introduced a major pain point for developers trying to access event properties inside asynchronous code.
Because React cleared the event object immediately after the
synchronous event handler finished executing, any attempt to access the
event object inside a setTimeout, a Promise, or an
asynchronous state update would result in null or
undefined values.
Consider this example, which caused bugs in React 16:
function MyComponent() {
const handleClick = (event) => {
// This works synchronously
console.log(event.target.value);
// This fails in React 16 and earlier
setTimeout(() => {
console.log(event.target.value); // Error: Cannot read property 'value' of null
}, 1000);
};
return <button onClick={handleClick}>Click Me</button>;
}To bypass this issue, developers had to call
event.persist(). This method told React to remove the
specific event from the pool, allowing its properties to remain intact
so they could be accessed asynchronously.
Why Event Pooling Was Removed in React 17
With the release of React 17, the React team officially removed event pooling.
Modern browsers have highly optimized garbage collection engines,
meaning the minor performance benefits of recycling event objects no
longer justified the developer confusion and bugs caused by pooled
events. Today, React creates a new event object for every event just
like native JavaScript does, allowing you to access event properties
inside asynchronous functions without ever needing to call
event.persist().