React ला तुमचे components अंदाज लावण्यायोग्य (predictable) हवे आहेत. त्याला तेच state आणि props द्या, आणि त्याने प्रत्येक वेळी तेच UI दाखवले पाहिजे. पण बहुतेक वास्तविक ॲप्लिकेशन्स त्या मर्यादेत (bubble) राहू शकत नाहीत. त्यांना बाहेरच्या गोष्टींशी संपर्क साधावा लागतो. डॅशबोर्डला सर्व्हरकडून ताज्या आकड्यांची गरज असते. चॅट विजेटला मेसेजसाठी लक्ष द्यावे लागते. टाइमरला टिक-टिक करावे लागते. ही ऑपरेशन्स 'side effects' आहेत आणि ती React च्या render cycle च्या बाहेर असतात. useEffect hook हे असे ठिकाण आहे जिथे तुम्ही ते गोंधळलेले आणि अनिश्चित काम ठेवता, जेणेकरून तुमचा component स्वतःमध्ये अचूक राहू शकेल.

Side Effects: useEffect मध्ये काय असावे

Side effect म्हणजे असे काहीही जे JSX रिटर्न करण्यापलीकडे जगाशी संपर्क साधते. React ची render phase ही 'pure' असायला हवी. जेव्हा तुम्ही डेटा fetch करणे, global variables मध्ये लिहिणे किंवा DOM ला listeners जोडणे सुरू करता, तेव्हा तुम्ही 'pure territory' च्या बाहेर पडता.

सामान्य उदाहरणांमध्ये खालील गोष्टींचा समावेश होतो:

  • API मधून डेटा fetch करणे
  • timers किंवा intervals सेट करणे
  • window किंवा document ला event listeners जोडणे
  • ब्राउझर टॅबचे title अपडेट करणे
  • WebSockets ला कनेक्ट करणे

या कामांमध्ये एक गोष्ट समान आहे: ती तुमच्या component च्या return statement मध्ये किंवा मुख्य render logic दरम्यान असायला नकोत. setInterval सारखे browser API थेट render body मध्ये कॉल करण्याचा प्रयत्न केल्यास ते प्रत्येक render वेळी कार्यान्वित होतील, ज्यामुळे duplicate timers तयार होतील आणि गोंधळ निर्माण होईल. हे काम वेगळे करण्यासाठी आणि ते योग्य वेळी चालवण्यासाठी useEffect अस्तित्वात आहे.

Dependency Array वेळेचे नियंत्रण (Timing) कसा करतो

useEffect चा दुसरा argument हा dependency array आहे, आणि class components कडून येणाऱ्या developers साठी हा गोंधळाचा सर्वात मोठा स्रोत आहे. याला व्हेरिएबल्सचा असा संच समजा ज्यावर React लक्ष ठेवते, जेणेकरून सध्याच्या render नंतर तुमचा effect वगळायचा की कार्यान्वित करायचा हे ठरवता येईल.

तुम्ही वारंवार वापरणार असे तीन पॅटर्न आहेत.

एकही dependency array न वापरणे. जर तुम्ही array पूर्णपणे वगळला, तर React असे गृहीत धरते की तुम्हाला पहिल्या render सह प्रत्येक render नंतर effect चालवायचा आहे. याची गरज क्वचितच पडते. जर तुमचा effect एखादी network request किंवा जड DOM operation करत असेल, तर प्रत्येक keystroke किंवा state च्या बदलावर ते चालवल्यामुळे performance खूप कमी होईल. हा पॅटर्न तेव्हाच वापरा जेव्हा तुम्हाला खरोखर काहीतरी पुन्हा चालवण्याची गरज असेल कारण कोणताही prop किंवा state बदलला असू शकतो आणि तुम्ही नेमका कोणता बदलला आहे हे सांगू शकत नाही.

रिकामी array []. हे React ला सांगते की component mount झाल्यानंतर आणि DOM तयार झाल्यानंतर लगेच एकदाच effect चालवावा. सुरुवातीचा डेटा fetch करण्यासाठी ही योग्य जागा आहे. उदाहरणार्थ, जर तुमचा component user profile डेटा लोड करत असेल, तर तुम्हाला ती request प्रोफाइल पेज दिसताच एकदाच कार्यान्वित करायची आहे, पेजच्या खाली असलेल्या फॉर्मसोबत युजरने प्रत्येक वेळी संवाद साधल्यावर नाही.

विशिष्ट व्हेरिएबल्ससह array [count]. हे एक अचूक साधन आहे. React या dependencies च्या सध्याच्या मूल्यांची तुलना मागील render मधील मूल्यांशी करते. जर त्यांपैकी काहीही बदलले, तर effect चालतो. जर यादीतील काहीही बदलले नाही, तर React तो effect पूर्णपणे वगळते.

जर तुम्ही ब्राउझर टॅबचे title एखाद्या state variable सोबत sync करत असाल, तर तुम्ही ते variable dependency array मध्ये टाकाल. त्यानंतर React फक्त ते मूल्य बदलल्यावरच title अपडेट करेल. ते वगळले, तर title जुनेच राहील. आणि जर तुम्ही असंबद्ध state variables टाकले, तर महत्त्वाच्या नसलेल्या बदलांसाठी title अपडेट करण्यात तुमचे cycles वाया जातील.

Cleanup करणे अनिवार्य आहे

काही effects मागे खुणा (footprints) सोडतात. टाइमर मोजत राहतो. Event listener चालू राहतो. WebSocket उघडे राहते. जेव्हा तुमचा component unmount होतो, किंवा जेव्हा dependencies बदलल्यामुळे effect पुन्हा चालतो, तेव्हा React मागील effect चा अवशेष (residue) आपोआप साफ करत नाही. हे तुमचे काम आहे.

तुम्ही useEffect च्या आतून एक function return करून cleanup function तयार करू शकता. React पुढचा effect लागू करण्यापूर्वी आणि component स्क्रीनवरून निघून गेल्यावर पुन्हा एकदा हे cleanup function कॉल करते.

तुम्ही खालील गोष्टींसाठी cleanup वापरले पाहिजे:

  • clearInterval किंवा clearTimeout वापरून intervals किंवा timeouts clear करणे
  • window, document, किंवा external nodes ला जोडलेले event listeners काढून टाकणे
  • data streams किंवा services मधून unsubscribe करणे

याकडे दुर्लक्ष केल्यास memory leaks होऊ शकतात. एक component mount होतो, scroll listener जोडतो, unmount होतो, पण तो listener तसाच राहतो. ब्राउझर तो callback आणि त्याद्वारे संदर्भित (reference) केलेले DOM nodes धरून ठेवतो. कालांतराने, विशेषतः जास्त navigation असलेल्या single-page applications मध्ये, हे 'ghosts' जमा होतात आणि टॅबचा वेग कमी करतात. याचे निराकरण सहसा फक्त काही ओळींचे असते: तुम्ही जे जोडले आहे ते काढून टाकणारे function return करा.

Production मध्ये जाणारे सामान्य चुका

साध्या पर्यायाची उपलब्धता असतानाही, अनुभवी डेव्हलपर्स देखील useEffect चा वापर करतात. कोड रिव्ह्यू दरम्यान खालील तीन पॅटर्न (patterns) धोक्याची घंटा (red flag) मानले पाहिजेत.

Infinite loops. जर एखादे state variable तुमच्या dependency array मध्ये असेल, तर useEffect च्या आत ते कधीही अपडेट करू नका, जोपर्यंत तुमच्याकडे तो सायकल तोडण्यासाठी एखादी gate condition नसेल. जर तुम्ही count वाचले, त्यात वाढ केली आणि count ला dependency म्हणून सूचीबद्ध केले, तर React तो बदल पाहतो, re-renders करतो, effect पुन्हा चालवतो, पुन्हा वाढ करतो आणि ब्राउझर लॉक करतो.

Unnecessary effects. अस्तित्वात असलेल्या props किंवा state मधून एखादे मूल्य (value) मोजण्यासाठी useEffect वापरू नका. जर तुम्ही ते render दरम्यान थेट मिळवू शकत असाल, तर तसेच करा. Derived values हे component body मध्ये किंवा useMemo वापरून केलेल्या memoized calculation मध्ये असायला हवेत. त्यांना effect मध्ये हलवल्यामुळे तुमचा logic विनाकारण render आणि effect phases मध्ये विभागला जातो आणि कोड समजून घेणे कठीण होते.

The wrong tool for user actions. use