Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
React ka event delegation, synthetic event wrapping aur root se bubbling.
React event listeners seedhe DOM elements par attach nahi karta. Iske bajaye, woh event delegation use karta hai â ek single listener root container par attach hoti hai (woh div jahan ReactDOM.createRoot() call kiya gaya tha). Jab koi bhi native event root tak bubble hota hai, React use intercept karta hai, ek SyntheticEvent object mein wrap karta hai, aur React component tree se dispatch karta hai.
Jab aap JSX mein onClick='{'handleClick'}' likhte hain, React us DOM node par addEventListener call nahi karta. Uski jagah, woh root container par 'click' events ke liye ek single listener register karta hai â poori app ke liye ek baar, har component ke liye ek baar nahi.
Jab aap koi button click karte hain, browser button par ek native click event fire karta hai, jo real DOM tree se hote hue document root tak bubble karta hai â jahan React ka listener wait kar raha hota hai.
React native event ko ek SyntheticEvent mein wrap karta hai â ek cross-browser normalized event object jo browser se regardless same API expose karta hai. Purane React versions mein, SyntheticEvents performance ke liye pooled aur reused hote the.
React target element se root tak fiber tree traverse karta hai, har fiber par jo onClick (ya dusra event) handlers milte hain unhe call karta hai. Yeh browser bubbling simulate karta hai lekin React ke virtual tree mein.
Native events ki tarah, React onClickCapture se capture phase handlers support karta hai. Yeh top-down fire hote hain (root se target tak) bubble phase handlers se pehle jo bottom-up fire hote hain (target se root tak).
Root par ek listener us type ke saare events handle karta hai. Har interactive element par listeners attach karne se bahut zyada efficient hai.
React ka cross-browser event wrapper. Browsers ke beech inconsistencies normalize karta hai. Raw access ke liye nativeEvent property expose karta hai.
Event target element se upar ancestor elements tak propagate karta hai. Zyaadatar React event handlers ka default phase.
Event root se neeche target tak bubble karne se pehle propagate karta hai. Capture phase ke liye onClickCapture use karo.
Event ko React ke simulated tree mein aage propagate hone se rokta hai. Native event nahi rokta jab tak e.nativeEvent par call na karo.
1// React attaches ONE listener to the root â not to each button:2// root.addEventListener('click', reactHandler)34function App() {5 return (6 <div onClick={() => console.log('div â bubble')}>7 <button8 onClick={(e) => {9 console.log('button â bubble');10 // e.stopPropagation() would stop div from firing11 }}12 onClickCapture={() => console.log('button â capture')}13 >14 Click me15 </button>16 </div>17 );18}1920// Click order:21// 1. button â capture (capture phase, top-down)22// 2. button â bubble (bubble phase, bottom-up)23// 3. div â bubble (bubble phase, continues up)
Event delegation React ko highly efficient banata hai â aapki app mein chahe kitne bhi buttons hon, har event type ke liye sirf ek native event listener hai. Iska matlab yeh bhi hai ki React dynamically add hone wale components ke events bhi intercept aur handle kar sakta hai, aur yeh React ke synthetic event system ko saare browsers mein consistently kaam karne deta hai.
You add a native `document.addEventListener('click', closeMenu)` to close a dropdown on outside click. Inside the dropdown, you call `e.stopPropagation()` on the React onClick â but the menu still closes.
React's stopPropagation stops propagation within React's synthetic event system (which uses delegation at the root). But the native listener on `document` has already received the event since React 17+ attaches to `root`, not `document`. The native handler fires before React can stop it.
Use `e.nativeEvent.stopImmediatePropagation()` to stop the native event from reaching other native listeners, or better yet, replace the native listener with a React `onClickCapture` on a wrapper div. Keep event handling within React's system to avoid mixed delegation conflicts.
Takeaway: React's event system runs inside a single delegated listener at the root container. Mixing React events with native `addEventListener` creates ordering conflicts. Prefer keeping all event logic within React's system for predictable behavior.
Legacy code from React 16 calls `e.persist()` in event handlers to use the event in async callbacks. After upgrading to React 18, you see that removing `e.persist()` works fine â but no one on the team understands why.
React 16 used event pooling â SyntheticEvent objects were reused after the handler returned, setting all properties to null. Accessing `e.target` in a setTimeout would return null unless you called `e.persist()`. Teams kept adding persist() defensively everywhere.
React 17+ removed event pooling entirely. SyntheticEvent objects are no longer reused â they persist naturally. All `e.persist()` calls can be safely removed. Understanding this change helps teams clean up legacy code and stop defensive coding patterns that are no longer needed.
Takeaway: React's event system evolves across versions. Event pooling removal (React 17), root-level delegation (React 17), and automatic batching in event handlers (React 18) are all changes that affect how you write event handling code. Stay current with the release notes.