React چاہتا ہے کہ آپ کے components قابلِ پیش گوئی (predictable) ہوں۔ اسے وہی state اور props دیں، اور اسے ہر بار ایک ہی طرح کا UI دکھانا چاہیے۔ لیکن زیادہ تر حقیقی ایپلی کیشنز اس محدود دائرے میں نہیں رہ سکتیں۔ انہیں باہر کی دنیا سے رابطہ کرنے کی ضرورت ہوتی ہے۔ ایک dashboard کو سرور سے تازہ اعداد و شمار کی ضرورت ہوتی ہے۔ ایک chat widget کو پیغامات سننے کی ضرورت ہوتی ہے۔ ایک timer کو چلنے کی ضرورت ہوتی ہے۔ یہ تمام آپریشنز side effects ہیں، اور یہ React کے render cycle سے باہر ہوتے ہیں۔ useEffect hook وہ جگہ ہے جہاں آپ یہ الجھا ہوا اور غیر یقینی کام رکھتے ہیں تاکہ آپ کا component خود شفاف (honest) رہے۔

Side Effects: useEffect کے اندر کیا ہونا چاہیے

Side effect سے مراد کوئی بھی ایسی چیز ہے جو JSX واپس کرنے کے علاوہ دنیا کے کسی اور حصے کو متاثر کرے۔ React کا render phase خالص (pure) ہونا چاہیے۔ جب آپ ڈیٹا fetch کرنا، global variables میں لکھنا، یا DOM کے ساتھ listeners منسلک کرنا شروع کرتے ہیں، تو آپ خالص حدود سے باہر نکل جاتے ہیں۔

عام مثالوں میں شامل ہیں:

  • API سے ڈیٹا fetch کرنا
  • Timers یا intervals سیٹ کرنا
  • window یا document میں event listeners شامل کرنا
  • Browser tab title کو اپ ڈیٹ کرنا
  • WebSockets سے منسلک ہونا

ان کاموں میں ایک بات مشترک ہے: یہ آپ کے component کے return statement یا مین render logic کے اندر نہیں ہونے چاہئیں۔ render body کے اندر براہ راست setInterval جیسی browser API کو کال کرنے کی کوشش کرنے سے یہ ہر render پر چلے گی، جس سے ڈپلیکیٹ timers بنیں گے اور غیر یقینی رویہ پیدا ہوگا۔ useEffect کا مقصد ہی اس کام کو الگ کرنا اور اسے صحیح وقت پر چلانا ہے۔

Dependency Array وقت (Timing) کو کیسے کنٹرول کرتا ہے

useEffect کا دوسرا argument dependency array ہے، اور یہ ان ڈویلپرز کے لیے سب سے بڑا الجھن کا باعث ہے جو class components سے منتقل ہو رہے ہیں۔ اسے ویری ایبلز کے ایک ایسے سیٹ کے طور پر سمجھیں جن پر React نظر رکھتا ہے تاکہ یہ فیصلہ کر سکے کہ موجودہ render کے بعد آپ کے effect کو چھوڑنا ہے یا چلانا ہے۔

تین پیٹرن ہیں جنہیں آپ بار بار استعمال کریں گے۔

کوئی dependency array نہیں۔ اگر آپ array کو مکمل طور پر چھوڑ دیتے ہیں، تو React فرض کرتا ہے کہ آپ چاہتے ہیں کہ effect پہلے render سمیت ہر ایک render کے بعد چلے۔ یہ شاذ و نادر ہی آپ کی ضرورت ہوتی ہے۔ اگر آپ کا effect کوئی network request یا بھاری DOM operation کرتا ہے، تو ہر keystroke یا state کی تبدیلی پر اسے چلانے سے پرفارمنس گر جائے گی۔ اس پیٹرن کو صرف اس وقت استعمال کریں جب آپ کو واقعی کسی چیز کو دوبارہ چلانے کی ضرورت ہو کیونکہ کوئی prop یا state تبدیل ہو سکتی ہے اور آپ یہ واضح نہیں کر سکتے کہ کون سی تبدیل ہوئی ہے۔

ایک خالی array []۔ یہ React کو بتاتا ہے کہ effect کو صرف ایک بار چلایا جائے، جیسے ہی component mount ہو اور DOM تیار ہو۔ یہ ابتدائی ڈیٹا fetches کے لیے صحیح جگہ ہے۔ مثال کے طور پر، اگر آپ کا component user profile data لوڈ کرتا ہے، تو آپ چاہتے ہیں کہ وہ request بالکل ایک بار چلے جب profile page ظاہر ہو، نہ کہ ہر بار جب صارف صفحے کے نیچے کسی فارم کے ساتھ بات چیت کرے۔

مخصوص ویری ایبلز کے ساتھ ایک array [count]۔ یہ ایک درست (precision) ٹول ہے۔ React ان dependencies کی موجودہ ویلیوز کا موازنہ پچھلے render کے دوران ان کی ویلیوز سے کرتا ہے۔ اگر ان میں سے کوئی بھی بدلی ہو، تو effect چلتا ہے۔ اگر فہرست میں کچھ بھی نہ بدلا ہو، تو React effect کو مکمل طور پر چھوڑ دیتا ہے۔

اگر آپ browser tab title کو کسی state variable کے ساتھ سنک (sync) کر رہے ہیں، تو آپ اس variable کو dependency array میں رکھیں گے۔ React پھر title کو صرف اس وقت اپ ڈیٹ کرے گا جب وہ value بدلے گی۔ اسے چھوڑ دیں، تو title پرانا (stale) رہے گا۔ غیر متعلقہ state variables ڈال دیں، تو آپ ان تبدیلیوں کے لیے title کو اپ ڈیٹ کرنے میں وقت ضائع کریں گے جن کا کوئی فائدہ نہیں۔

Cleanup لازمی ہے

کچھ effects اپنے پیچھے نشانات چھوڑ جاتے ہیں۔ ایک timer گنتی جاری رکھتا ہے۔ ایک event listener چلتا رہتا ہے۔ ایک WebSocket کھلا رہتا ہے۔ جب آپ کا component unmount ہوتا ہے، یا یہاں تک کہ جب کوئی effect دوبارہ چلتا ہے کیونکہ اس کی dependencies بدل گئی ہیں، تو React خود بخود پچھلے effect کے اثرات کو صاف نہیں کرتا۔ یہ آپ کا کام ہے۔

آپ useEffect کے اندر سے ایک function واپس (return) کر کے cleanup function بنا سکتے ہیں۔ React اگلے effect کو لاگو کرنے سے پہلے اور ایک بار پھر جب component اسکرین سے ہٹ جاتا ہے، اس cleanup کو کال کرتا ہے۔

آپ کو ان کاموں کے لیے cleanup استعمال کرنا چاہیے:

  • clearInterval یا clearTimeout کے ذریعے intervals یا timeouts کو صاف کرنا
  • window، document, یا بیرونی nodes پر شامل کیے گئے event listeners کو ہٹانا
  • Data streams یا services سے unsubscribe کرنا

اس پر نظر انداز کریں، تو آپ کو memory leaks کا سامنا کرنا پڑے گا۔ ایک component mount ہوتا ہے، scroll listener منسلک کرتا ہے، unmount ہوتا ہے، اور listener وہیں رہتا ہے۔ براؤزر callback اور ان DOM nodes کو تھامے رکھتا ہے جن کا وہ حوالہ دیتا ہے۔ وقت کے ساتھ، خاص طور پر بھاری نیویگیشن والی single-page applications میں، یہ "بھوت" (ghosts) جمع ہو جاتے ہیں اور tab کو سست کر دیتے ہیں۔ اس کا حل عام طور پر صرف چند لائنیں ہیں: ایک ایسا function return کریں جو اس چیز کو ہٹا دے جو آپ نے شامل کی تھی۔

Common Mistakes That Ship to Production

Even experienced developers reach for useEffect when a simpler option exists. Here are three patterns that should raise a red flag during code review.

Infinite loops. Never update a state variable inside useEffect if that same variable sits in your dependency array, unless you have a gate condition that breaks the cycle. If you read count, increment it, and list count as a dependency, React sees the change, re-renders, runs the effect again, increments again, and locks the browser.

Unnecessary effects. Do not use useEffect to calculate a value from existing props or state. If you can derive it directly during render, just do it. Derived values belong in the component body or in a memoized calculation with useMemo. Moving them into an effect splits your logic across render and effect phases for no benefit and makes the code harder to follow.

The wrong tool for user actions. `use