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 का event delegation, synthetic event wrapping और root से bubbling।
React, DOM elements पर directly event listeners attach नहीं करता। इसके बजाय, यह event delegation उपयोग करता है — root container (जहाँ ReactDOM.createRoot() call हुआ) पर एक single listener attach होता है। जब कोई भी native event root तक bubble करता है, React उसे intercept करता है, उसे SyntheticEvent object में wrap करता है, और React component tree में dispatch करता है।
जब आप JSX में onClick='{'handleClick'}' लिखते हैं, React उस DOM node पर addEventListener call नहीं करता। इसके बजाय, यह root container पर 'click' events के लिए एक single listener register करता है — पूरे app के लिए एक बार, प्रत्येक component के लिए नहीं।
जब आप button click करते हैं, browser button पर native click event fire करता है, जो real DOM tree से document root तक bubble करता है — जहाँ React का listener इंतज़ार कर रहा है।
React native event को SyntheticEvent में wrap करता है — एक cross-browser normalized event object जो browser की परवाह किए बिना same API expose करता है। पुराने React versions में, SyntheticEvents performance के लिए pooled और reused होते थे।
React fiber tree को target element से root तक traverse करता है, प्रत्येक fiber पर onClick (या अन्य event) handlers call करता है। यह browser bubbling simulate करता है लेकिन React के virtual tree में।
Native events की तरह, React onClickCapture के ज़रिए capture phase handlers support करता है। ये top-down (root → target) fire होते हैं, bubble phase handlers के bottom-up (target → root) fire होने से पहले।
Root पर एक listener उस type के सभी events handle करता है। हर interactive element पर listeners attach करने से बहुत अधिक efficient है।
React का cross-browser event wrapper। Browsers के बीच inconsistencies normalize करता है। Raw access के लिए nativeEvent property expose करता है।
Event target element से ancestor elements तक ऊपर propagate होता है। अधिकांश React event handlers के लिए default phase।
Event bubbling से पहले root से target तक नीचे propagate होता है। Capture phase के लिए onClickCapture उपयोग करें।
Event को React के simulated tree में आगे propagate होने से रोकता है। Native event को नहीं रोकता जब तक e.nativeEvent पर call न हो।
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 को highly efficient बनाता है — आपके app में चाहे जितने buttons हों, प्रत्येक event type के लिए केवल एक native event listener होता है। इसका अर्थ है React dynamically add किए गए components के events भी intercept और handle कर सकता है, और यह React के synthetic event system को सभी browsers में consistently काम करने देता है।
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.