How to Implement Event Pooling in React
This article explains the concept of event pooling in React, how to
work with it in legacy projects, and how modern React versions handle
event optimization. You will learn how React historically reused event
objects to improve performance, how to use e.persist() to
retain event properties in asynchronous code, and why event pooling was
ultimately removed in React 17.
Understanding Event Pooling in Legacy React
In React 16 and earlier, React used a technique called Event Pooling to improve performance. Instead of creating a new synthetic event object for every single user interaction, React maintained a single pool of event objects.
When an event was triggered, React populated a pooled event object
with data and passed it to your event handler. Once the event handler
finished executing, React cleared all properties on the event object
(setting them to null) and returned the object to the pool
for reuse.
Because of this reuse, you could not access the event object
asynchronously (such as inside a setTimeout, a Promise, or
an asynchronous state update) because the object’s properties would
already be cleared.
How to Implement e.persist() in React 16 and Earlier
If you are working with React 16 or earlier and need to access event
properties inside an asynchronous callback, you must explicitly tell
React not to release the event back into the pool. You do this by
calling e.persist() on the synthetic event.
Here is how to implement it:
import React from 'react';
function SearchInput() {
const handleInputChange = (e) => {
// Call persist to retain the event object for asynchronous access
e.persist();
setTimeout(() => {
// Without e.persist(), e.target.value would throw an error or be null
console.log(`Searching for: ${e.target.value}`);
}, 1000);
};
return <input type="text" onChange={handleInputChange} />;
}
export default SearchInput;By calling e.persist(), React removes the event from the
pool, allowing you to safely reference its properties in asynchronous
operations.
Event Pooling in Modern React (React 17 and Later)
If you are using React 17 or newer, you do not need to
implement event pooling or use e.persist().
The React team completely removed event pooling in React 17 because modern browsers handle garbage collection efficiently enough that the performance benefits of pooling are negligible, while the system itself caused frequent developer confusion.
In modern React:
- Synthetic event objects are not reused.
- You can access event properties freely inside asynchronous
functions,
setTimeout, or state updates without callinge.persist(). e.persist()still exists as a function, but it does nothing and is safe to remove from your codebase.
Here is how the same asynchronous code is written in React 17 and 18:
import React from 'react';
function SearchInput() {
const handleInputChange = (e) => {
// No e.persist() is required in React 17+
setTimeout(() => {
console.log(`Searching for: ${e.target.value}`);
}, 1000);
};
return <input type="text" onChange={handleInputChange} />;
}
export default SearchInput;