प्रत्येक React डेव्हलपरला शेवटी एकाच प्रश्नाचा सामना करावा लागतो: मी Context वापरावे की ही Redux ची समस्या आहे? जर तुम्ही फक्त काही महिन्यांपासून डेव्हलपमेंट करत असाल, तर इंटरनेटवरील गोंधळामुळे असे वाटते की यापैकी एकच निवडणे आवश्यक आहे. काही ट्युटोरियल्स Redux ला जुनाट (legacy) समजतात, तर काही असा इशारा देतात की Context फक्त to-do list पर्यंतच मर्यादित राहू शकतो. या दोन्ही टोकाच्या गोष्टी उपयुक्त नाहीत. सत्य हे आहे की ही साधने वेगवेगळ्या प्रकारच्या समस्या सोडवतात आणि योग्य निवड करणे हे तुमचे ॲप्लिकेशन प्रत्यक्षात काय करते यावर अवलंबून असते.

Prop Drilling ची समस्या

स्टेट मॅनेजमेंटची (state management) रणनीती निवडण्यापूर्वी, दोन्ही साधने नेमकी कोणती समस्या सोडवण्याचा प्रयत्न करत आहेत हे समजून घेणे फायदेशीर ठरते. समजा तुम्ही एक e-commerce साइट तयार करत आहात. तुम्ही App component च्या टॉप-लेव्हलला युजरचा प्रोफाईल डेटा मिळवता. खाली फूटरमध्ये (footer), एका लहान AccountLink component ला त्या प्रोफाईल फोटोची गरज आहे. ग्लोबल स्टोअरशिवाय, तो user object Home, त्यानंतर Header, मग NavContainer, त्यानंतर UserDropdown आणि शेवटी AccountLink पर्यंत प्रवास करावा लागतो. दरम्यानचे प्रत्येक लेयर अशा डेटाला स्पर्श करतो ज्याचा त्याला वापर करायचा नाहीये. यालाच 'prop drilling' म्हणतात.

Prop drilling मुळे components नाजूक (brittle) बनतात. Refactoring करणे जोखमीचे होते कारण मधला एखादा घटक काढल्यास संपूर्ण साखळी तुटते. Reusability वर परिणाम होतो कारण components ला असे props लागतात जे ते फक्त खाली पाठवत असतात. Context आणि Redux दोन्ही हे थेट शेअर केलेल्या डेटाला सबस्क्राईब करण्याची सुविधा देऊन ही समस्या दूर करतात. परंतु ते डेटा देण्याची पद्धत आणि त्यासाठी लागणारा खर्च यामध्ये लवकरच फरक पडतो.

जेव्हा React Context API योग्य ठरते

React Context हे लायब्ररीमध्येच समाविष्ट आहे. कोणतेही अतिरिक्त npm इन्स्टॉल्स, बिल्ड कॉन्फिगरेशन किंवा boilerplate फाइल्सची गरज नाही. तुम्ही एक context object तयार करता, तुमच्या ट्रीचा (tree) काही भाग Provider मध्ये गुंडाळता आणि कोणत्याही नेस्टेड component मध्ये useContext वापरून त्याची व्हॅल्यू मिळवता. या साधेपणामुळे, Context अशा लहान ते मध्यम प्रकल्पांसाठी उत्तम आहे जिथे स्टेटमधील बदल क्वचितच होतात आणि त्या स्टेटचे स्वरूप तुलनेने साधे (flat) असते.

UI थीम्सचा विचार करा. एखादा युजर कदाचित प्रत्येक सेशनमध्ये एकदाच light आणि dark मोडमध्ये बदल करतो. ही व्हॅल्यू प्रत्येक styled component पर्यंत पोहोचते, परंतु ती इतक्या क्वचित बदलते की परफॉर्मन्सची चिंता येत नाही. Authentication status हे आणखी एक उत्तम उदाहरण आहे. एकदा युजर लॉग इन झाला की, isAuthenticated फ्लॅग आणि user object अनेक पेज नेव्हिगेशन्समध्ये स्थिर राहतात. भाषा किंवा localization सेटिंग्ज देखील याच पद्धतीने काम करतात. हे असे व्यापक आणि संथ बदलणारे संकेत आहेत ज्यांची अनेक components ला गरज असते, परंतु कमीच components त्यात बदल करतात.

अडचण अशी आहे की Context अपडेट्स कसे हाताळतो. जेव्हा Context Provider ची व्हॅल्यू बदलते, तेव्हा React त्या context चा वापर करणाऱ्या प्रत्येक single component ला पुन्हा रेंडर (re-render) करतो. लहान ॲप्लिकेशनमध्ये तुम्हाला याची जाणीव होणार नाही. परंतु मोठ्या ॲप्लिकेशनमध्ये, जर तुम्ही वेगाने बदलणारा डेटा मोठ्या प्रमाणावर वापरल्या जाणाऱ्या Context मध्ये ठेवला, तर यामुळे अनावश्यक रेंडर्सचा (renders) मोठा साठा तयार होऊ शकतो. तुम्ही अस्थिरता (volatility) कमी करण्यासाठी context विभागू शकता, परंतु त्या क्षणी तुम्ही मॅन्युअली अशा ऑप्टिमायझेशन उपायांवर काम करत असता जे दुसरे साधन आधीच सोडवते.

जेव्हा Redux Toolkit ची गरज भासते

Redux Toolkit अशा ॲप्लिकेशन्ससाठी डिझाइन केले आहे जिथे state गुंतागुंतीची आहे, अपडेट्स वारंवार होतात आणि अनेक दूरवरच्या फीचर्सना एकमेकांशी न आदळता तोच डेटा वाचण्याची आणि लिहिण्याची गरज असते. शॉपिंग कार्टचे उदाहरण घ्या. युजर प्रॉडक्ट कार्डमधून एखादी वस्तू जोडतो. हेडरमधील कार्ट आयकॉनला त्याच्या बॅज काउंटमध्ये अपडेट व्हायला हवे. लाइन आयटम्स दाखवण्यासाठी एक साइडबार बाहेर येतो. डिस्काउंट कोड इनपुट व्हॅलिडेशन रन करते. नंतर चेकआउट पेज कार्टमधील मजकूर वाचते. तो डेटा संपूर्ण ट्रीमधील असंबंधित components द्वारे स्पर्श केला जातो आणि तो वारंवार बदलतो.

Redux Toolkit हे एका सेंट्रलाइज्ड स्टोअर (centralized store) आणि स्टेटच्या स्पष्ट स्लाईसेस (slices) द्वारे हे सोडवते. Components useSelector वापरून त्यांना आवश्यक असलेल्या डेटाच्या लहान भागांनाच सबस्क्राईब करतात. जर रिअल-टाइम डॅशबोर्डमध्ये स्टॉकची किंमत अपडेट होत असेल, तर युजर प्रोफाईल सेटिंग्ज दाखवणारा component जागृत होत नाही. Redux अंतर्गत 'reference equality checks' वापरते जेणेकरून सबस्क्रिप्शन्स सूक्ष्म (granular) राहतील. जेव्हा तुमच्या components ची संख्या शेकडोमध्ये जाते, तेव्हा हे अत्यंत महत्त्वाचे ठरते.

Redux तुम्हाला एक प्रेडिक्टेबल (predictable) डेटा फ्लो देखील देते. स्टेटमधील बदल रिड्यूसर्स (reducers) द्वारे हाताळल्या जाणाऱ्या डिस्पॅच केलेल्या ॲक्शन्स (dispatched actions) द्वारे होतात. हे ऐकायला तांत्रिक (jargon) वाटू शकते, परंतु प्रत्यक्षात याचा अर्थ असा आहे की तुम्ही तुमच्या कोडबेसमध्ये addToCart शोधून कार्टमध्ये बदल करणाऱ्या प्रत्येक कोड पाथचा शोध घेऊ शकता. मोठ्या टीममध्ये, हा करार बग्स रोखतो. याउलट, Context फक्त एक व्हॅल्यू आणि एक सेटर (setter) आहे. कोणताही consumer setState कॉल करू शकतो, आणि चुकीच्या व्हॅल्यूचा उगम शोधणे म्हणजे अनेक components मध्ये ब्रेकपॉइंट्स लावणे होय.

ते खरोखर कुठे वेगळे ठरतात

कामगिरीची वैशिष्ट्ये (Performance characteristics) ही गोष्ट इतर कोणत्याही गोष्टीपेक्षा या टूल्सना एकमेकांपासून वेगळे करते. Context सर्व ग्राहकांना (consumers) बिनशर्त नवीन मूल्य प्रसारित करतो. Redux फक्त अशा सबस्क्रायबर्सना सूचित करतो ज्यांचा निवडलेला स्लाईस (slice) बदलला आहे. जर तुम्ही रिअल-टाइम स्टॉक डॅशबोर्ड बनवत असाल जिथे दर सेकंदाला कोट्स रिफ्रेश होतात, तर Context मुळे संपूर्ण ॲप्लिकेशनमध्ये 'ग्लोबल री-रेंडरिंग'चा (global re-render) मोठा भार पडू शकतो. Redux मुळे फक्त टिकर सेल (ticker cell) आणि स्पार्कलाइन चार्ट (sparkline chart) पुन्हा मोजले (recompute) जातील.

डीबगिंग (Debugging) हे दुसरे क्षेत्र आहे जिथे जटिल ॲप्समध्ये Redux आघाडीवर आहे. Redux DevTools तुम्हाला 'टाइम-ट्रॅव्हल डीबगिंग' (time-travel debugging) देते. तुम्ही प्रत्येक 'डिस्पॅच्ड ॲक्शन' (dispatched action) मधून मागे जाऊ शकता आणि स्टेट (state) रिव्हॉइंड होताना पाहू शकता. शिपिंग कॅल्क्युलेशन, पेमेंट व्हॅलिडेशन आणि एरर रिकव्हरीसह असलेल्या मल्टी-स्टेप चेकआउट फ्लोमध्ये, बगला कारणीभूत ठरलेली नेमकी प्रक्रिया पुन्हा प्ले (replay) करणे अत्यंत मोलाचे ठरते. Context हे स्टँडर्ड React DevTools वर अवलंबून असते. तुम्ही सध्याची context व्हॅल्यूज तपासू शकता, परंतु त्यात इन-बिल्ट ॲक्शन लॉग किंवा स्टेट डिफ व्ह्यूअर (state diff viewer) नाही. तुम्हाला पुन्हा एकदा console.log चा वापर करावा लागतो.

मिडलवेअर आणि साइड इफेक्ट्स (Middleware and side effects) हे Redux च्या मूळ स्वरूपाचा (DNA) भाग आहेत. Redux Toolkit मध्ये createAsyncThunk समाविष्ट आहे आणि ते डेटा-फेचिंग लायब्ररीजसोबत सुलभतेने जोडले जाते. तुम्ही Redux डेटा फ्लोमध्येच API कॉल आयोजित करणे, लोडिंग स्पिनर दाखवणे, नेटवर्क फेल्युअर हाताळणे आणि रिझल्ट कॅश करणे, या सर्व गोष्टी करू शकता. Context मध्ये असिंक्रोनस लॉजिकसाठी (asynchronous logic) कोणताही इन-बिल्ट पॅटर्न नाही. एकतर तुम्हाला कंपोनंट्समध्ये डेटा फेच करून तो रिझल्ट Context मध्ये ढकलावा लागतो, किंवा तुम्हाला स्वतःच्या बनवलेल्या असिंक्रोनस युटिलिटीजमध्ये प्रोव्हायडर्स (providers) गुंडाळावे लागतात. हे काम करते, पण ते तात्पुरते (ad hoc) असते.

सेटअप खर्च (Setup cost) यामध्ये Context स्पष्टपणे जिंकते. थीम प्रोव्हायडर (theme provider) तयार करण्यासाठी साधारण पाच मिनिटे लागतात. Redux Toolkit साठी स्टोअर फाईल तयार करणे, स्लाईसेस (slices) परिभाषित करणे आणि तुमच्या ॲप्लिकेशनला प्रोव्हायडरमध्ये (Provider) गुंडाळणे आवश्यक असते. जुन्या Redux आणि त्याच्या प्रचंड बॉयलरप्लेट (boilerplate) कोडमुळे हे काम आठवडाभर चालणारे काम नव्हते, तरीही Context च्या तुलनेत यात जास्त सेटअप लागतो. वीकेंड साईड प्रोजेक्ट किंवा तीन रूट्स असलेल्या डॅशबोर्डसाठी, हा अतिरिक्त भार (overhead) घेण्यासारखा नसेल.

एकाच ॲप्लिकेशनमध्ये दोन्हीचा वापर करणे

तुम्हाला एकाच गटाची निष्ठा राखण्याची गरज नाही. अनेक प्रोडक्शन ॲप्लिकेशन्स ग्लोबल UI शेलच्या कामांसाठी Context आणि डोमेन-हेवी बिझनेस डेटासाठी Redux वापरतात. एक सामान्य पद्धत म्हणजे थीम, लोकेल (locale) आणि कदाचित एक हलका ऑथ फ्लॅग (auth flag) Context मध्ये ठेवणे, कारण प्रत्येक रूटला त्यांची गरज असते आणि ते क्वचितच बदलतात. दरम्यान, ऑर्डर मॅनेजमेंट सिस्टम, नोटिफिकेशन सेंटर आणि डेटा टेबल्स Redux मध्ये असतात, जिथे वारंवार होणारे अपडेट्स आणि क्रॉस-कंपोनंट लॉजिकसाठी अचूक नियंत्रणाची गरज असते.

हा हायब्रिड दृष्टिकोन स्टॅटिक थीम ऑब्जेक्टसाठी पूर्ण Redux स्टोअर वापरण्याची सक्ती न करता सोप्या गोष्टी सोप्या ठेवतो. यामुळे तुमचे Redux स्लाईसेस अशा UI घटक (UI chrome) ने भरून जात नाहीत ज्यांना सुरुवातीपासूनच इंडस्ट्रियल-ग्रेड स्टेट मॅनेजमेंटची गरज नव्हती.

मुख्य निष्कर्ष (The Real Takeaway)

जड (heavy) टूल निवडणे म्हणजे काही विशेष सन्मान नाही. तुमची स्टेट किती वेळा बदलते, किती कंपोनंट्स तिला स्पर्श करतात आणि तुम्हाला टीमच्या सीमांच्या पलीकडे म्यूटेशन्स (mutations) ट्रॅक करण्याची गरज आहे का, हे पाहून सुरुवात करा. जर तुम्ही मध्यम आकाराच्या ॲपमध्ये हळूहळू बदलणाऱ्या आणि मोठ्या प्रमाणावर शेअर केल्या जाणाऱ्या व्हॅल्यूज मॅनेज करत असाल, तर Context पुरेसा आहे. जर तुमची स्टेट वारंवार बदलते, असंबद्ध फीचर्समध्ये पसरलेली आहे आणि तिला स्पष्ट ऑडिट ट्रेलची (audit trail) गरज असेल, तर Redux Toolkit तुमचे काम सोपे करेल.

तुमच्या प्रोजेक्टच्या स्वरूपानुसार निवडा, कॉन्फरन्समधील भाषणे किंवा GitHub स्टार्सनुसार नाही. पन्नास वस्तूंपर्यंत पोहोचणाऱ्या शॉपिंग कार्टला आपोआप Redux ची गरज नसते आणि थीम टॉगलला ग्लोबल स्टोअरची गरज नसते. समस्येनुसार योग्य टूल निवडा, आणि हायप सायकल (hype cycle) संपल्यानंतरही तुमचा कोडबेस मेंटेन करण्यायोग्य (maintainable) राहील.