स्टेट प्रबंधन मुश्किल है क्योंकि ऐप कई सत्य स्रोतों, असिंक डेटा, UI इंटरैक्शंस और प्रदर्शन ट्रेडऑफ़ को संभालते हैं। बग घटाने के लिए व्यवहारिक पैटर्न सीखें।

फ्रंटएंड ऐप में, स्टेट बस वही डेटा है जिस पर आपका UI निर्भर करता है और जो समय के साथ बदल सकता है।
जब स्टेट बदलता है, स्क्रीन को उसी के अनुरूप अपडेट होना चाहिए। अगर स्क्रीन अपडेट नहीं होती, असंगत तरीके से अपडेट होती है, या पुराने और नए मानों का मिश्रण दिखाती है, तो आप तुरंत “स्टेट प्रॉब्लम” महसूस करते हैं—बटन जो डिसेबल रह जाते हैं, टोटल्स जो मेल नहीं खाते, या ऐसा व्यू जो यूजर की हाल की क्रिया को नहीं दर्शाता।
स्टेट छोटे और बड़े इंटरैक्शंस दोनों में दिखता है, जैसे:
इनमें से कुछ “अस्थायी” होते हैं (जैसे चुना हुआ टैब), जबकि कुछ “महत्वपूर्ण” महसूस होते हैं (जैसे कार्ट)। वे सब स्टेट हैं क्योंकि वे प्रभावित करते हैं कि अभी UI क्या रेंडर करे।
एक साधारण वेरिएबल सिर्फ़ उसी जगह मायने रखता है जहाँ वह रहता है। स्टेट अलग है क्योंकि उसके साथ कुछ नियम आते हैं:
स्टेट मैनेजमेंट का असली उद्देश्य डेटा स्टोर करना नहीं—बल्कि अपडेट्स को पूर्वानुमानित बनाना है ताकि UI संगत रहे। जब आप जवाब दे सकें “क्या बदला, कब और क्यों,” तब स्टेट मैनेजेबल हो जाता है। जब आप नहीं बता पाते, तो साधारण फीचर्स भी सरप्राइज़ में बदल जाते हैं।
एक फ्रंटएंड प्रोजेक्ट के आरम्भ में, स्टेट लगभग नीरस लगता है—अच्छी तरह से। आपके पास एक कम्पोनेंट, एक इनपुट, और एक साफ़ अपडेट होता है। यूजर फ़ील्ड में टाइप करता है, आप वैल्यू सेव करते हैं, और UI री-रेंडर होता है। सब कुछ दिखाई देता है, तर्कसंगत और contained होता है।
एक सिंगल टेक्स्ट इनपुट सोचिए जो आपने टाइप की गई चीज़ का प्रीव्यू दिखाता है:
इस सेटअप में, स्टेट मूल रूप से: एक वेरिएबल जो समय के साथ बदलता है। आप बता सकते हैं कि यह कहाँ स्टोर है और कहाँ अपडेट होता है।
लोकल स्टेट इसलिए काम करता है क्योंकि मानसिक मॉडल कोड ढांचे से मेल खाता है:
यहां तक कि अगर आप React जैसे फ्रेमवर्क का इस्तेमाल करते हैं, आपको आर्किटेक्चर के बारे में गहराई से सोचना नहीं पड़ता। डिफ़ॉल्ट्स पर्याप्त होते हैं।
जैसे ही ऐप “एक पेज में एक विजेट” नहीं रह जाता और “एक प्रोडक्ट” बन जाता है, स्टेट एक ही जगह नहीं रहता।
अब वही डेटा कई जगहों पर ज़रूरी हो सकता है:
एक प्रोफ़ाइल नाम हेडर में दिख सकता है, सेटिंग पेज में एडिट किया जा सकता है, तेज़ लोडिंग के लिए कैश किया जा सकता है, और पर्सनलाइज़्ड वेलकम में इस्तेमाल हो सकता है। अचानक सवाल यह नहीं है “मैं इस वैल्यू को कैसे स्टोर करूँ?” बल्कि “यह वैल्यू कहां रहनी चाहिए ताकि वह हर जगह सही रहे?”
स्टेट जटिलता फीचर्स के साथ धीरे-धीरे नहीं बढ़ती—यह छलांग लगाती है।
एक दूसरी जगह जोड़ना जो वही डेटा पढ़ती है, “दो गुना कठिन” नहीं है। यह सम्मन्वय की समस्याएँ लाता है: व्यूज़ को संगत रखना, स्टेल वैल्यूज़ रोकना, तय करना कि क्या किसे-update करेगा, और टाइमिंग संभालना। जब आपके पास कुछ शेयर किए गए पीस और असिंक्रोनस वर्क होते हैं, तो व्यवहार कठिन हो सकता है—यद्यपि हर फ़ीचर अकेले में सरल दिखता है।
जब वही “सत्य” एक से अधिक जगह पर स्टोर हो जाता है, स्टेट कष्टदायक हो जाता है। हर कॉपी drift कर सकती है, और अब आपका UI खुद से बहस करता है।
ज्यादातर ऐप्स में कई ऐसी जगहें होती हैं जो “सत्य” रख सकती हैं:
ये सभी कुछ स्टेट के मालिक हो सकते हैं। दिक्कत तब होती है जब वे सब एक जैसे स्टेट का मालिक बनना शुरू कर देते हैं।
एक आम पैटर्न: सर्वर डेटा फ़ेच करें, फिर उसे लोकल स्टेट में कॉपी कर लें “ताकि हम एडिट कर सकें।” उदाहरण: आप एक यूजर प्रोफाइल लोड करते हैं और formState = userFromApi सेट कर देते हैं। बाद में सर्वर रीफ़ेच करता है (या किसी अन्य टैब ने रिकॉर्ड अपडेट कर दिया), और अब आपके पास दो वर्ज़न होते हैं: कैश एक कहता है कुछ और, आपका फॉर्म कुछ और।
डुप्लिकेशन “हेल्पफुल” ट्रांसफ़ॉर्मेशन से भी आ जाता है: items और itemsCount दोनों स्टोर करना, या selectedId और selectedItem दोनों रखना।
जब कई स्रोत हों, तो बग्स आमतौर पर कुछ इस तरह दिखते हैं:
हर स्टेट पीस के लिए, एक मालिक चुनें—वह जगह जहाँ अपडेट किए जाते हैं—और बाकी सब को प्रोजेक्शन मानें (रीड-ओनली, व्युत्पन्न, या एक दिशा में सिंक)। अगर आप मालिक नहीं बता सकते, तो सम्भवतः आप वही सत्य दो बार स्टोर कर रहे हैं।
कई फ्रंटएंड स्टेट सरल इसलिए लगता है क्योंकि वह सिंक्रोनस है: यूजर क्लिक करता है, आप वैल्यू सेट करते हैं, UI अपडेट होता है। साइड-इफेक्ट्स उस साफ स्टेप-बाय-स्टेप कहानी को तोड़ देते हैं।
साइड-इफेक्ट्स वे क्रियाएँ हैं जो आपके कम्पोनेंट की प्योर “रेंडर डेटा के आधार पर” मॉडल के बाहर जाती हैं:
इनमें से हर एक बाद में फायर कर सकता है, असफल हो सकता है, या एक से ज़्यादा बार चल सकता है।
असिंक्रोनस अपडेट्स समय को एक वेरिएबल बना देते हैं। अब आप सिर्फ़ “क्या हुआ” नहीं सोचते, बल्कि “क्या अभी भी हो सकता है” के बारे में सोचते हैं। दो रिक्वेस्ट ओवरलैप कर सकती हैं। एक धीमा रिस्पॉन्स नए वाले के बाद आ सकता है। एक कम्पोनेंट अनमाउंट हो सकता है जबकि असिंक्रोनस कॉलबैक अभी भी स्टेट अपडेट करने की कोशिश कर रहा हो।
इसीलिए बग्स अक्सर इस तरह दिखते हैं:
बिखरे हुए isLoading जैसे बूलियन छिड़कने की बजाय, असिंक्रोनस वर्क को एक छोटे स्टेट मशीन की तरह सोचें:
डेटा और स्टेटस दोनों को साथ रखें, और एक पहचानकर्ता (जैसे रिक्वेस्ट आईडी या क्वेरी की) रखें ताकि आप लेट रिस्पॉन्स को नज़रअंदाज़ कर सकें। इससे “अभी UI क्या दिखाए?” का सवाल सटीक बन जाता है, अनुमान नहीं।
कई स्टेट समस्याएँ एक सरल गड़बड़ से शुरू होती हैं: “यूजर अभी क्या कर रहा है” को उसी तरह मान लेना जैसा “बैकएंड क्या कहता है।” दोनों समय के साथ बदल सकते हैं, पर उनके नियम अलग होते हैं।
UI स्टेट अस्थायी और इंटरैक्शन-चालित है। यह उस क्षण के लिए स्क्रीन को वैसा ही दिखाने के लिए मौजूद है जैसा यूजर अपेक्षा करता है।
उदाहरण: मोडलों का खुला/बंद होना, सक्रिय फ़िल्टर्स, सर्च इनपुट ड्राफ्ट, होवर/फोकस, कौन सा टैब चुना है, पेजिनेशन UI (वर्तमान पेज, पेज साइज, स्क्रॉल पोज़िशन)।
यह स्टेट आमतौर पर पेज या कम्पोनेंट ट्री तक ही सीमित होता है। नेविगेट करते समय इसे रीसेट होना ठीक है।
सर्वर स्टेट API से आया डेटा है: यूजर प्रोफाइल, प्रोडक्ट लिस्ट, परमिशन, नोटिफिकेशन्स, सेव्ड सेटिंग्स। यह “रिमोट सत्य” है जो बिना आपके UI कुछ करे बदल भी सकता है (कोई और एडिट करे, सर्वर री-कैल्कुलेट करे, बैकग्राउंड जॉब अपडेट करे)।
क्योंकि यह रिमोट है, इसे मेटाडेटा चाहिए: लोडिंग/एरर स्टेट, कैश टाइमस्टैम्प, रीट्राय, इनवैलिडेशन।
अगर आप UI ड्राफ्ट्स को सर्वर डेटा में स्टोर कर देते हैं, तो रीफ़ेच लोकल एडिट्स को मिटा सकता है। अगर आप सर्वर रिस्पॉन्स को UI स्टेट में बिना कैश नियमों के रखते हैं, तो आप स्टेल डेटा, डुप्लिकेट फ़ेच और असंगत स्क्रीन से जूझेंगे।
एक सामान्य फेल्योर मोड: यूजर एक फॉर्म एडिट कर रहा है जबकि बैकग्राउंड रीफ़ेच फिनिश होता है, और आने वाला रिस्पॉन्स ड्राफ्ट को ओवरराइट कर देता है।
सर्वर स्टेट को कैशिंग पैटर्न्स (फेच, कैश, इनवैलिडेट, फ़ोकस पर रीफ़ेच) से मैनेज करें और उसे साझा व असिंक्रोनस मानें।
UI स्टेट को UI टूल्स (लोकल कम्पोनेंट स्टेट, और सच में शेयर करने के लिए context) से मैनेज करें, और ड्राफ्ट्स को तब तक अलग रखें जब तक आप इरादतन उन्हें सर्वर पर “सेव” न करें।
व्युत्पन्न स्टेट किसी भी वैल्यू को कहते हैं जिसे आप दूसरे स्टेट से गणना कर सकते हैं: लाइन आइटम्स से कार्ट टोटल, मूल लिस्ट + सर्च क्वेरी से फ़िल्टर्ड लिस्ट, या फ़ील्ड वैल्यूज़ और वॅलिडेशन नियमों से canSubmit फ्लैग।
इन्हें स्टोर करना लुभावना होता है क्योंकि यह सुविधाजनक लगता है (“मैं total भी स्टोर कर लूँगा”)। पर जैसे ही इनपुट कई जगह बदले जाते हैं, ड्रिफ्ट का जोखिम आता है: स्टोर किया total आइटम्स से मेल नहीं खाता, फ़िल्टर्ड लिस्ट करंट क्वेरी को नहीं दिखाती, या सबमिट बटन एरर ठीक करने के बाद भी डिसेबल रहता है। ये बग्स परेशान करते हैं क्योंकि अलग-अलग स्टेट वैरिएबल अकेले में सही दिखते हैं—सिर्फ़ आपस में असंगत होते हैं।
सुरक्षित पैटर्न यह है: सत्य के न्यूनतम स्त्रोत को स्टोर करें, और बाकी सब कुछ रीड टाइम पर कैलकुलेट करें। React में यह एक साधारण फ़ंक्शन हो सकता है, या मेमोइज़्ड कैलकुलेशन।
const items = useCartItems();
const total = items.reduce((sum, item) =\u003e sum + item.price * item.qty, 0);
const filtered = products.filter(p =\u003e p.name.includes(query));
बड़े ऐप्स में, “सेलेक्टर्स” (या कंप्यूटेड गेटर्स) इस विचार को औपचारिक बनाते हैं: एक जगह पर परिभाषित होता है कि total, filteredProducts, visibleTodos कैसे व्युत्पन्न होते हैं, और हर कम्पोनेंट वही लॉजिक उपयोग करता है।
हर रेंडर पर कंप्यूट करना सामान्यतः ठीक है। तब कैश करें जब आपने वास्तविक लागत मापी हो: महँगे ट्रांसफ़ॉर्मेशन, विशाल सूचियाँ, या कई कम्पोनेंट्स में साझा व्युत्पन्न मान। मेमोइज़ेशन (useMemo, सेलेक्टर मेमोइज़ेशन) का उपयोग करें ताकि कैश कीज़ सच्चे इनपुट हों—नहीं तो आप फिर से ड्रिफ्ट के करीब होंगे, केवल परफॉरमेंस बहाना पहनाकर।
स्टेट तब कष्टप्रद हो जाता है जब यह स्पष्ट न हो कि इसका मालिक कौन है।
किसी स्टेट पीस का मालिक वह जगह है जिसे उसे अपडेट करने का अधिकार है। बाकी UI पार्ट्स उसे रीड कर सकते हैं (props, context, selectors के जरिए), पर सीधे बदलना नहीं चाहिए।
स्पष्ट ओनरशिप दो सवालों का जवाब देती है:
जब ये सीमाएँ धुंधली होती हैं, आप conflicting अपडेट्स, “यह कब बदला?” जैसी घटनाएँ, और रियूज़ करने में मुश्किल कम्पोनेंट्स देखते हैं।
स्टेट को ग्लोबल स्टोर (या टॉप-लेवल context) में रखना साफ़ लगता है: कुछ भी एक्सेस कर सकता है और आप prop drilling से बचते हैं। पर ट्रेडऑफ है अनइंटेंडेड कैपलिंग—अचानक unrelated स्क्रीन एक ही वैल्यू पर निर्भर करते हैं, और छोटे बदलाव पूरे ऐप में प्रभाव डालते हैं।
ग्लोबल स्टेट उन चीज़ों के लिए अच्छा है जो सच में क्रॉस-कटिंग हों, जैसे वर्तमान यूजर सेशन, ऐप-व्यापी फीचर फ्लैग, या साझा नोटिफिकेशन 큐।
आम पैटर्न: लोकल से शुरू करें और तब ही स्टेट को निकटतम कॉमन पेरेंट तक उठाएँ जब दो सिबलिंग्स को समन्वय की ज़रूरत हो।
अगर केवल एक कम्पोनेंट को स्टेट चाहिए, तो वहीं रखें। अगर कई कम्पोनेंट्स को चाहिए, तो सबसे छोटे साझा मालिक तक उठाएँ। अगर कई दूरस्थ हिस्सों को चाहिए, तब ग्लोबल पर विचार करें।
स्टेट को जहाँ उपयोग होता है वहाँ पास रखें जब तक कि शेयरिंग आवश्यक न हो।
यह कम्पोनेंट्स को समझने में आसान रखता है, आकस्मिक निर्भरताओं को घटाता है, और भविष्य के रिफैक्टर्स कम डरावने बनाता है क्योंकि कम हिस्से एक ही डेटा को म्यूटेट करने की अनुमति रखते हैं।
फ्रंटएंड ऐप्स “सिंगल-थ्रेडेड” लगते हैं, पर यूजर इनपुट, टाइमर, एनीमेशन, और नेटवर्क रिक्वेस्ट सब स्वतंत्र रूप से चलते हैं। इसका मतलब है कई अपडेट एक साथ इन-फ़्लाइट हो सकते हैं—और वे ज़रूरी नहीं कि उसी क्रम में खत्म हों जिस क्रम में शुरू हुए थे।
एक सामान्य टकराव: UI के दो हिस्से एक ही स्टेट अपडेट करें।
query अपडेट करता है।query (या उसी परिणाम सूची) को बदल देता है जब चेन changed होता है।अलग-अलग रूप से, हर अपडेट सही है। एक साथ, वे एक-दूसरे को ओवरराइट कर सकते हैं टाइमिंग के हिसाब से। और भी बुरा, आप एक पुराने क्वेरी के परिणाम दिखा सकते हैं जबकि UI नए फ़िल्टर्स दिखाता है।
रेस कंडीशंस तब आती हैं जब आप रिक्वेस्ट A फायर करते हैं, फिर जल्दी से रिक्वेस्ट B करते हैं—पर रिक्वेस्ट A आख़िर में बाद में लौटता है।
उदाहरण: यूजर टाइप करता है “c”, “ca”, “cat”。 अगर “c” रिक्वेस्ट धीमा है और “cat” तेज़ है, UI पहले “cat” परिणाम दिखा सकता है और फिर स्टेल “c” परिणाम से ओवरराइट हो सकता है जब पुराना रिस्पॉन्स आए।
बग सूक्ष्म है क्योंकि हर कुछ “काम किया”—पर गलत क्रम में।
आप आमतौर पर इन में से एक रणनीति चाहते हैं:
AbortController)।एक सरल रिक्वेस्ट ID तरीका:
let latestRequestId = 0;
async function fetchResults(query) {
const requestId = ++latestRequestId;
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
const data = await res.json();
if (requestId !== latestRequestId) return; // stale response
setResults(data);
}
ऑप्टिमिस्टिक अपडेट्स UI को फ़ुर्तीला बनाते हैं: आप स्क्रीन को सर्वर कन्फ़र्म होने से पहले अपडेट करते हैं। पर समवर्तीता मान्यताओं को तोड़ सकती है:
ऑप्टिमिज़्म को सुरक्षित रखने के लिए अक्सर स्पष्ट मेल-प्रतिस्थापन नियम चाहिए: पेंडिंग एक्शन को ट्रैक करें, सर्वर रिस्पॉन्स को क्रम में लागू करें, और अगर रोलबैक करना है तो किसी जानकार चेकपॉइंट तक रोलबैक करें (न कि “जो UI अभी दिख रहा है”)।
स्टेट अपडेट्स “फ़्री” नहीं होते। जब स्टेट बदलता है, ऐप को यह तय करना पड़ता है कि स्क्रीन के किन हिस्सों पर असर पड़ सकता है और फिर नए रियलिटी को दर्शाने का काम करना पड़ता है: वैल्यूज़ री-कैल्कुलेट करना, UI री-रेंडर करना, फ़ॉर्मेटिंग लॉजिक फिर से चलाना, और कभी-कभी री-फ़ेच या री-वॅलिडेट करना। अगर यह चैन रिएक्शन ज़रूरत से बड़ा है, यूज़र इसे लैग, जैंक, या बटन के धीमे रिस्पॉन्स के रूप में महसूस करता है।
एक टॉगल अनायास ही बहुत सारा अतिरिक्त काम ट्रिगर कर सकता है:
परिणाम सिर्फ तकनीकी नहीं—यह अनुभवात्मक होता है: टाइपिंग देर लगती है, एनीमेशन हिचकिचाते हैं, और इंटरफ़ेस वह “स्नैपी” क्वालिटी खो देता है जिसे लोग polished प्रोडक्ट से जोड़ते हैं।
सबसे सामान्य कारणों में से एक है बहुत चौड़ा स्टेट: एक “बड़ा बकेट” ऑब्जेक्ट जिसमें कई असंबंधित जानकारी होती है। किसी भी फ़ील्ड को अपडेट करने पर पूरा बकेट नया लगने लगता है, इसलिए अधिक UI जाग उठता है।
एक और ट्रैप है व्युत्पन्न मानों को स्टेट में रखना और उन्हें मैनुअली अपडेट करना। यह अक्सर अतिरिक्त अपडेट्स (और अतिरिक्त UI वर्क) पैदा करता है सिर्फ़ सब कुछ सिंक में रखने के लिए।
स्टेट को छोटे-छोटे हिस्सों में बाँटें। असंबंधित चिंताओं को अलग रखें ताकि सर्च इनपुट बदलने पर पूरे पेज के परिणाम न रिफ्रेश हों।
डेटा नॉर्मलाइज़ करें। एक ही आइटम को कई जगह स्टोर करने की बजाय उसे एक बार रखें और संदर्भित करें। इससे रिपीट अपडेट्स घटेंगे और “चेंज स्टॉर्म” से बचाव होगा जहाँ एक एडिट कई कॉपियों को रिप्लेस कर देता है।
व्युत्पन्न मान मेमोइज़ करें। अगर किसी मान को अन्य स्टेट से कैलकुलेट किया जा सकता है (जैसे फ़िल्टर्ड रिज़ल्ट्स), तो उस कैलकुलेशन को कैश करें ताकि यह तभी री-कम्प्यूट हो जब इनपुट सचमुच बदलें।
अच्छा परफॉर्मेंस-मन वाले स्टेट मैनेजमेंट ज़्यादातर कंटेन्मेंट के बारे में है: अपडेट्स छोटे से छोटे एरिया को प्रभावित करें, और महँगा वर्क तभी हो जब वास्तव में ज़रूरत हो। जब यह सच होता है, यूज़र्स फ्रेमवर्क को भूल जाते हैं और इंटरफ़ेस पर भरोसा करने लगते हैं।
स्टेट बग अक्सर व्यक्तिगत महसूस होते हैं: UI “गलत” है, पर आप सबसे साधारण सवाल का जवाब नहीं दे पाते—किसने इस वैल्यू को बदला और कब? अगर कोई नंबर फ्लिप हो जाता है, बैनर गायब हो जाता है, या बटन खुद-ब-खुद डिसेबल हो जाता है, आपको अनुमान नहीं बल्कि टाइमलाइन चाहिए।
सबसे तेज़ रास्ता स्पष्ट अपडेट फ्लो है। चाहे आप reducers, events, या स्टोर का उपयोग करें, एक पैटर्न अपनाएँ जहाँ:
setShippingMethod('express'), न कि updateStuff)साफ़ एक्शन लॉगिंग डिबगिंग को “स्क्रीन घूरना” से बदलकर “रसीद का पालन करना” बना देती है। साधारण कंसोल लॉग्स (एक्शन नाम + मुख्य फ़ील्ड्स) भी यह काम कर देते हैं।
हर रेंडर को टेस्ट करने की कोशिश न करें। बल्कि उन हिस्सों को टेस्ट करें जो प्योर लॉजिक की तरह व्यवहार करते हैं:
यह मिश्रण दोनों “मैथ बग्स” और वास्तविक-वर्ल्ड वायरिंग इश्यू पकड़ता है।
असिंक्रोनस समस्याएँ गैप्स में छिपी होती हैं। उन गैप्स को दिखाने के लिए न्यूनतम मेटाडेटा जोड़ें:
फिर जब कोई लेट रिस्पॉन्स नए वाले को ओवरराइट करे, आप इसे तुरंत प्रमाणित कर सकें—और आत्मविश्वास के साथ ठीक कर सकें।
स्टेट टूल चुनना आसान तब होता है जब आप उसे डिज़ाइन डिसिजन का परिणाम मानें, न कि शुरुआत। लाइब्रेरी की तुलना करने से पहले अपने स्टेट बाउंड्री मैप करें: क्या बिल्कुल लोकल है, क्या शेयर करना है, और क्या वास्तव में “सर्वर डेटा” है जिसे आप फ़ेच और सिंक करेंगे।
व्यावहारिक निर्णय के लिए कुछ बाधाएँ देखें:
अगर आप “हम हर जगह X इस्तेमाल करेंगे” से शुरू करते हैं, तो आप गलत चीज़ें गलत जगह पर स्टोर कर देंगे। पहले ओनरशिप से शुरू करें: कौन इस वैल्यू को अपडेट करता है, कौन पढ़ता है, और बदलने पर क्या होना चाहिए।
कई ऐप्स के लिए अच्छा समाधान होता है सर्वर-स्टेट लाइब्रेरी API डेटा के लिए और एक छोटा UI-स्टेट सॉल्यूशन क्लाइंट-ऑनली चिंताओं जैसे मोडल्स, फ़िल्टर्स, या ड्राफ्ट फॉर्म वैल्यूज़ के लिए। लक्ष्य स्पष्टता है: हर प्रकार की स्टेट वहाँ रहे जहाँ उसे समझना आसान हो।
अगर आप स्टेट बाउंड्री और असिंक्रोनस फ़्लो पर प्रयोग कर रहे हैं, तो Koder.ai “ट्राइ करो, ऑब्जर्व करो, रिफ़ाइन करो” लूप को तेज कर सकता है। क्योंकि यह चैट से एजेंट-आधारित वर्कफ़्लो के ज़रिये React फ्रंटेंड (और Go + PostgreSQL बैकएंड) जेनरेट करता है, आप लोकल बनाम ग्लोबल, सर्वर कैश बनाम UI ड्राफ्ट जैसे वैकल्पिक मालिकाना मॉडलों को तेजी से प्रोटोटाइप कर सकते हैं और फिर वही रखें जो पूर्वानुमानित रहे।
दो व्यावहारिक फीचर मददगार हैं: Planning Mode (बिल्ड करने से पहले स्टेट मॉडल को आउटलाइन करने के लिए) और snapshots + rollback (रिफैक्टर जैसे “व्युत्पन्न स्टेट हटाएँ” या “रिक्वेस्ट IDs जोड़ें” सुरक्षित परीक्षण के लिए) बिना काम कर रही बेसलाइन खोए।
स्टेट तब आसान होता है जब आप इसे डिज़ाइन प्रॉब्लम की तरह ट्रीट करें: तय करें कौन इसका मालिक है, यह क्या दर्शाता है, और यह कैसे बदलता है। जब भी कोई कम्पोनेंट “रहस्यमयी” महसूस करे, इस चेकलिस्ट का उपयोग करें।
पूछें: किस ऐप भाग के लिए यह डेटा ज़िम्मेदार है? स्टेट को जहाँ उपयोग होता है मौजूद रखें, और तभी ऊपर उठाएँ जब कई हिस्सों को वाकई समन्वय चाहिए।
अगर आप किसी चीज़ को अन्य स्टेट से निकाल सकते हैं, तो उसे स्टोर मत करें।
items, filterText)।visibleItems) रेंडर के दौरान या मेमोइज़ेशन के जरिए कैलकुलेट करें।असिंक्रोनस वर्क तब स्पष्ट होता है जब आप उसे सीधे मॉडल करते हैं:
status: 'idle' | 'loading' | 'success' | 'error', साथ में data और error।isLoading, isFetching, isSaving, hasLoaded, …) बनाम एक ही स्टेटसकमी के लिए लक्ष्य रखें: “यह कैसे इस स्थिति में आया?” बग्स कम हों, परिवर्तन पाँच फाइलें छूने की ज़रूरत न करें, और एक मानसिक मॉडल जहाँ आप एक जगह इशारा कर सकें और कह सकें: यहाँ सत्य रहता है।