How to Update Synthetic Events in React
This article explains how to handle and update Synthetic Events in React. You will learn how React manages these events, the crucial differences between React 16 and React 17+ regarding event pooling, and the best practices for capturing and updating event data during asynchronous operations.
Understanding React Synthetic Events
A Synthetic Event is a cross-browser wrapper around the browser’s
native event. React wraps native events to ensure that your code behaves
consistently across different browsers. Synthetic events have the same
interface as native events, including methods like
preventDefault() and stopPropagation().
The Shift in React 17: No More Event Pooling
In React 16 and earlier, React used event pooling.
This meant that Synthetic Event objects were reused for performance
reasons. Once an event callback was executed, all properties on the
event object were nullified, making it impossible to access the event
asynchronously without calling event.persist().
Starting with React 17, event pooling was removed.
Synthetic Event properties no longer disappear after the callback is
executed. You can now access event properties directly inside
asynchronous code (such as setTimeout or promise chains)
without needing to update or persist the event manually.
How to Update State Using Synthetic Events
Because Synthetic Events represent read-only user actions, you do not update the event object itself. Instead, you use the data from the event to update your component’s state.
Here is the standard pattern for updating state using a Synthetic Event:
import React, { useState } from 'react';
function TextInput() {
const [value, setValue] = useState('');
const handleChange = (event) => {
// Access the synthetic event's target value and update state
setValue(event.target.value);
};
return <input type="text" value={value} onChange={handleChange} />;
}Best Practices for Asynchronous Updates
If you need to use event data inside an asynchronous function, the safest and most efficient practice is to extract the values you need immediately, rather than passing the entire event object into the asynchronous scope.
Recommended Approach: Value Extraction
Extracting the properties directly from the event object ensures your code remains clean, easy to test, and highly performant.
const handleSearch = (event) => {
// Extract the value immediately
const query = event.target.value;
// Use the extracted value in an asynchronous operation
setTimeout(() => {
console.log(`Searching for: ${query}`);
}, 1000);
};Legacy Approach: Event Persistence (React 16 and older)
If you are maintaining an older React application (React 16 or below)
and must pass the entire event to an asynchronous function, you must
call event.persist(). This removes the event from the pool
and prevents its properties from being nullified.
const handleLegacyChange = (event) => {
// Prevents React from clearing the event properties
event.persist();
setTimeout(() => {
// Safe to access in React 16 because of event.persist()
console.log(event.target.value);
}, 1000);
};