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.
Effects कब चलते हैं, cleanup का समय और dependency tracking।
useEffect, React components को external systems — browser APIs, third-party libraries, network requests, और subscriptions — के साथ synchronize करने का primary hook है। यह browser के screen paint करने के बाद चलता है, जिससे यह non-blocking होता है। प्रत्येक effect optionally एक cleanup function return करता है जिसे React effect फिर से चलाने से पहले और component unmount होने पर call करता है।
React DOM mutations commit करता है, browser screen paint करता है, और फिर React asynchronously आपके useEffect callbacks चलाता है। यह order ensure करता है कि effects initial render को कभी block नहीं करते — user तुरंत content देखता है।
React Object.is() equality का उपयोग करके current deps array की तुलना पिछले render के deps से करता है। यदि कोई dep बदला, effect re-run schedule होता है। No deps array = हर render के बाद चलो। Empty array [] = mount के बाद एक बार चलो।
यदि आपका effect एक function return करता है, React उसे cleanup के रूप में store करता है। Effect को फिर से चलाने से पहले (क्योंकि कोई dep बदला), React पहले पिछली cleanup call करता है। Component unmount होने पर, React आखिरी cleanup call करता है।
StrictMode में, React intentionally हर component को mount → unmount → remount करता है ताकि ऐसे effects surface हो सकें जो properly clean up नहीं करते। Double invocation केवल development में होता है। इसीलिए proper cleanup non-negotiable है।
useLayoutEffect में useEffect के समान semantics हैं लेकिन DOM mutations के बाद और browser paint से पहले synchronously fire होता है। इसे तब उपयोग करें जब आपके effect को DOM measurements read करने और user कुछ देखने से पहले corrections apply करने की ज़रूरत हो।
Re-run frequency control करता है। [] = mount only। [a, b] = जब a या b बदले। No array = हर render। React Object.is() से compare करता है — objects/arrays को deps में डालने से बचें।
आपके effect से return होने वाला function। Effect re-run (dep changed) से पहले और component unmount होने पर call होता है। Fetches cancel करने, timers clear करने, unsubscribe करने के लिए उपयोग होता है।
जब एक effect पुराने render से state/props capture करता है लेकिन updated values पाने के लिए कभी re-run नहीं होता। Variable को deps में add करने या ref उपयोग करने से fix होता है।
DOM mutation के बाद, paint से पहले synchronously fire होता है। Painting block करता है — इसे fast रखें। DOM measurements (getBoundingClientRect, scroll position) के लिए उपयोग करें।
किसी भी DOM mutation से पहले fire होता है। CSS-in-JS libraries के लिए intended है ताकि layout से पहले style rules synchronously inject कर सकें। General application code के लिए नहीं।
1// 1. Event subscription — must clean up2useEffect(() => {3 window.addEventListener('resize', handleResize);4 return () => window.removeEventListener('resize', handleResize);5}, []); // mount once, clean up on unmount67// 2. Fetch with cancellation (AbortController)8useEffect(() => {9 const controller = new AbortController();1011 fetch('/api/data', { signal: controller.signal })12 .then(res => res.json())13 .then(setData)14 .catch(err => {15 if (err.name !== 'AbortError') throw err; // ignore cancellation16 });1718 return () => controller.abort(); // cancel if dep changes or unmount19}, [userId]);2021// 3. useLayoutEffect for DOM measurement22useLayoutEffect(() => {23 const height = ref.current.getBoundingClientRect().height;24 setContainerHeight(height); // applied before paint — no flicker25}, [content]);
useEffect React में सबसे commonly misused hook है। Effects को सही करना — correct deps, proper cleanup, right timing — ऐसे apps build करने के लिए essential है जो memory leak न करें, extra network requests न करें, और stale data bugs न हों। Mental model shift है: 'effects synchronization mechanisms हैं', 'lifecycle events' नहीं। आप React को बता रहे हैं कि outside world के साथ sync में कैसे रहें, mount/update/unmount callbacks में hook नहीं कर रहे।
A developer writes `useEffect(() => { fetchData() })` without a dependency array. The app makes thousands of API calls per second, the browser freezes, and the API rate limits the user.
No dependency array means the effect runs AFTER EVERY RENDER. fetchData sets state → state change triggers re-render → re-render fires the effect → effect calls fetchData → sets state → infinite loop. Each loop iteration also creates a new network request.
Add the correct dependency array: `useEffect(() => { fetchData() }, [])` for mount-only, or `useEffect(() => { fetchData(query) }, [query])` for re-fetch when query changes. The dependency array tells React's effect scheduler when to skip re-execution.
Takeaway: The dependency array is not optional decoration — it's the core control mechanism of useEffect. No array = every render. Empty array = mount only. Specific deps = run when those values change. Getting this wrong is the #1 source of useEffect bugs.
A countdown timer displays the time remaining. You use `setInterval` inside useEffect with an empty dependency array. The timer shows the same number forever instead of counting down.
The useEffect callback closes over the initial `count` value (e.g., 60). setInterval calls `setCount(count - 1)` every second, but `count` is always 60 inside the closure (captured at mount time). Result: `setCount(59)` every second — never changes from 59.
Use the functional updater form: `setCount(prev => prev - 1)`. The updater receives the CURRENT state, not the stale closure value. Alternatively, store count in a ref and sync it every render. The functional form is React's escape hatch for stale closures in effects.
Takeaway: Effects capture values at the time they're created (closures). For intervals and timeouts that need current state, always use the functional updater `setState(prev => ...)` or a ref pattern to bypass the stale closure.