|
3 weeks ago | |
---|---|---|
.. | ||
README.md | 3 weeks ago | |
assignment.md | 4 weeks ago |
README.md
बैंकिंग ऐप बनाएं भाग 4: स्टेट मैनेजमेंट की अवधारणाएँ
प्री-लेक्चर क्विज़
परिचय
जैसे-जैसे एक वेब एप्लिकेशन बढ़ता है, डेटा प्रवाह को ट्रैक करना चुनौतीपूर्ण हो जाता है। कौन सा कोड डेटा प्राप्त करता है, कौन सा पेज इसे उपयोग करता है, इसे कब और कहाँ अपडेट करने की आवश्यकता है... यह आसानी से गड़बड़ कोड में बदल सकता है जिसे बनाए रखना मुश्किल है। यह विशेष रूप से तब सच है जब आपको अपने ऐप के विभिन्न पेजों के बीच डेटा साझा करने की आवश्यकता होती है, जैसे उपयोगकर्ता डेटा। स्टेट मैनेजमेंट की अवधारणा हमेशा सभी प्रकार के प्रोग्रामों में मौजूद रही है, लेकिन जैसे-जैसे वेब ऐप्स की जटिलता बढ़ती जा रही है, यह अब विकास के दौरान विचार करने का एक प्रमुख बिंदु बन गया है।
इस अंतिम भाग में, हम उस ऐप पर विचार करेंगे जिसे हमने बनाया है ताकि स्टेट को बेहतर तरीके से प्रबंधित किया जा सके, जिससे ब्राउज़र को किसी भी समय रिफ्रेश करने का समर्थन मिले और उपयोगकर्ता सत्रों के बीच डेटा को बनाए रखा जा सके।
पूर्वापेक्षा
आपको इस पाठ के लिए वेब ऐप के डेटा फेचिंग भाग को पूरा करना होगा। आपको Node.js इंस्टॉल करना होगा और सर्वर API को लोकल रूप से चलाना होगा ताकि आप अकाउंट डेटा प्रबंधित कर सकें।
आप यह कमांड टर्मिनल में चलाकर जांच सकते हैं कि सर्वर सही तरीके से चल रहा है:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
स्टेट मैनेजमेंट पर पुनर्विचार
पिछले पाठ में, हमने अपने ऐप में स्टेट की एक बुनियादी अवधारणा पेश की थी जिसमें account
नामक एक ग्लोबल वेरिएबल था जो वर्तमान में लॉग इन किए गए उपयोगकर्ता के बैंक डेटा को संग्रहीत करता है। हालांकि, हमारे वर्तमान कार्यान्वयन में कुछ खामियां हैं। डैशबोर्ड पर रहते हुए पेज को रिफ्रेश करने का प्रयास करें। क्या होता है?
वर्तमान कोड में 3 समस्याएं हैं:
- स्टेट संरक्षित नहीं है, क्योंकि ब्राउज़र रिफ्रेश आपको लॉगिन पेज पर वापस ले जाता है।
- स्टेट को संशोधित करने वाले कई फंक्शन हैं। जैसे-जैसे ऐप बढ़ता है, यह परिवर्तनों को ट्रैक करना मुश्किल बना सकता है और एक को अपडेट करना भूलना आसान हो जाता है।
- स्टेट साफ नहीं किया गया है, इसलिए जब आप लॉगआउट पर क्लिक करते हैं तो अकाउंट डेटा अभी भी वहां होता है, भले ही आप लॉगिन पेज पर हों।
हम इन समस्याओं को एक-एक करके हल करने के लिए अपने कोड को अपडेट कर सकते हैं, लेकिन इससे कोड का अधिक डुप्लीकेशन होगा और ऐप अधिक जटिल और बनाए रखने में कठिन हो जाएगा। या हम कुछ मिनटों के लिए रुक सकते हैं और अपनी रणनीति पर पुनर्विचार कर सकते हैं।
हम वास्तव में यहां कौन सी समस्याओं को हल करने की कोशिश कर रहे हैं?
स्टेट मैनेजमेंट का उद्देश्य इन दो विशेष समस्याओं को हल करने के लिए एक अच्छा दृष्टिकोण खोजना है:
- ऐप में डेटा प्रवाह को समझने योग्य कैसे रखें?
- स्टेट डेटा को हमेशा उपयोगकर्ता इंटरफ़ेस के साथ (और इसके विपरीत) सिंक में कैसे रखें?
एक बार जब आप इनका ध्यान रख लेते हैं, तो आपके पास जो अन्य समस्याएं हो सकती हैं, वे या तो पहले ही हल हो चुकी होंगी या उन्हें हल करना आसान हो गया होगा। इन समस्याओं को हल करने के लिए कई संभावित दृष्टिकोण हैं, लेकिन हम एक सामान्य समाधान के साथ जाएंगे जिसमें डेटा और इसे बदलने के तरीकों को केंद्रीकृत करना शामिल है। डेटा प्रवाह इस प्रकार होगा:
हम यहां उस हिस्से को कवर नहीं करेंगे जहां डेटा स्वचालित रूप से व्यू अपडेट को ट्रिगर करता है, क्योंकि यह रिएक्टिव प्रोग्रामिंग की अधिक उन्नत अवधारणाओं से जुड़ा हुआ है। यदि आप गहराई से अध्ययन करने के इच्छुक हैं, तो यह एक अच्छा विषय है।
✅ स्टेट मैनेजमेंट के लिए कई लाइब्रेरी उपलब्ध हैं, जिनमें Redux एक लोकप्रिय विकल्प है। इसके उपयोग किए गए अवधारणाओं और पैटर्न को देखें क्योंकि यह अक्सर यह समझने का एक अच्छा तरीका होता है कि बड़े वेब ऐप्स में आप किन संभावित समस्याओं का सामना कर सकते हैं और उन्हें कैसे हल किया जा सकता है।
कार्य
हम थोड़ा रिफैक्टरिंग से शुरुआत करेंगे। account
डिक्लेरेशन को बदलें:
let account = null;
से:
let state = {
account: null
};
यह विचार हमारे ऐप डेटा को एक सिंगल स्टेट ऑब्जेक्ट में केंद्रीकृत करने का है। फिलहाल हमारे पास स्टेट में केवल account
है, इसलिए यह ज्यादा नहीं बदलता है, लेकिन यह विकास के लिए एक रास्ता बनाता है।
हमें इसका उपयोग करने वाले फंक्शन को भी अपडेट करना होगा। register()
और login()
फंक्शन में, account = ...
को state.account = ...
से बदलें;
updateDashboard()
फंक्शन के शीर्ष पर, यह लाइन जोड़ें:
const account = state.account;
यह रिफैक्टरिंग अपने आप में बहुत सुधार नहीं लाती है, लेकिन विचार अगले परिवर्तनों के लिए नींव रखना था।
डेटा परिवर्तनों को ट्रैक करें
अब जब हमने अपना डेटा स्टोर करने के लिए state
ऑब्जेक्ट स्थापित कर लिया है, तो अगला कदम अपडेट को केंद्रीकृत करना है। लक्ष्य यह है कि किसी भी परिवर्तन और उनके होने के समय को ट्रैक करना आसान हो जाए।
state
ऑब्जेक्ट में परिवर्तन करने से बचने के लिए, इसे immutable मानना भी एक अच्छा अभ्यास है, जिसका अर्थ है कि इसे बिल्कुल भी संशोधित नहीं किया जा सकता। इसका मतलब यह भी है कि यदि आप इसमें कुछ भी बदलना चाहते हैं तो आपको एक नया स्टेट ऑब्जेक्ट बनाना होगा। ऐसा करके, आप संभावित अवांछित साइड इफेक्ट्स के बारे में सुरक्षा बनाते हैं और अपने ऐप में नई सुविधाओं को लागू करने जैसे कि undo/redo को सक्षम करने की संभावनाओं को खोलते हैं, साथ ही इसे डिबग करना आसान बनाते हैं। उदाहरण के लिए, आप स्टेट में किए गए हर बदलाव को लॉग कर सकते हैं और बग के स्रोत को समझने के लिए परिवर्तनों का इतिहास रख सकते हैं।
जावास्क्रिप्ट में, आप Object.freeze()
का उपयोग करके ऑब्जेक्ट का एक immutable संस्करण बना सकते हैं। यदि आप immutable ऑब्जेक्ट में परिवर्तन करने का प्रयास करते हैं, तो एक अपवाद उत्पन्न होगा।
✅ क्या आप जानते हैं कि shallow और deep immutable ऑब्जेक्ट में क्या अंतर है? आप इसके बारे में यहां पढ़ सकते हैं।
कार्य
आइए एक नया updateState()
फंक्शन बनाएं:
function updateState(property, newData) {
state = Object.freeze({
...state,
[property]: newData
});
}
इस फंक्शन में, हम एक नया स्टेट ऑब्जेक्ट बना रहे हैं और पिछले स्टेट से डेटा को स्प्रेड (...
) ऑपरेटर का उपयोग करके कॉपी कर रहे हैं। फिर हम ब्रैकेट नोटेशन [property]
का उपयोग करके स्टेट ऑब्जेक्ट की एक विशेष प्रॉपर्टी को नए डेटा के साथ ओवरराइड करते हैं। अंत में, हम Object.freeze()
का उपयोग करके ऑब्जेक्ट को लॉक कर देते हैं ताकि संशोधन रोके जा सकें। फिलहाल हमारे स्टेट में केवल account
प्रॉपर्टी संग्रहीत है, लेकिन इस दृष्टिकोण के साथ आप स्टेट में जितनी चाहें उतनी प्रॉपर्टी जोड़ सकते हैं।
हम यह सुनिश्चित करने के लिए state
इनिशियलाइज़ेशन को भी अपडेट करेंगे कि प्रारंभिक स्टेट भी फ्रीज हो:
let state = Object.freeze({
account: null
});
इसके बाद, register
फंक्शन को अपडेट करें और state.account = result;
असाइनमेंट को बदलें:
updateState('account', result);
login
फंक्शन के साथ भी ऐसा ही करें, state.account = data;
को बदलें:
updateState('account', data);
अब हम उपयोगकर्ता द्वारा लॉगआउट पर क्लिक करने पर अकाउंट डेटा साफ न होने की समस्या को ठीक करने का अवसर लेंगे।
एक नया फंक्शन logout()
बनाएं:
function logout() {
updateState('account', null);
navigate('/login');
}
updateDashboard()
में, रीडायरेक्शन return navigate('/login');
को return logout();
से बदलें;
एक नया अकाउंट रजिस्टर करें, लॉगआउट करें और फिर से लॉगिन करें यह जांचने के लिए कि सब कुछ अभी भी सही तरीके से काम कर रहा है।
टिप: आप ब्राउज़र के डेवलपमेंट टूल्स में कंसोल खोलकर और
updateState()
के नीचेconsole.log(state)
जोड़कर सभी स्टेट परिवर्तनों को देख सकते हैं।
स्टेट को संरक्षित करें
अधिकांश वेब ऐप्स को सही तरीके से काम करने के लिए डेटा को संरक्षित करने की आवश्यकता होती है। सभी महत्वपूर्ण डेटा आमतौर पर डेटाबेस में संग्रहीत होते हैं और सर्वर API के माध्यम से एक्सेस किए जाते हैं, जैसे कि हमारे मामले में उपयोगकर्ता अकाउंट डेटा। लेकिन कभी-कभी, उपयोगकर्ता अनुभव को बेहतर बनाने या लोडिंग प्रदर्शन में सुधार करने के लिए ब्राउज़र में चल रहे क्लाइंट ऐप पर कुछ डेटा संरक्षित करना भी दिलचस्प होता है।
जब आप अपने ब्राउज़र में डेटा संरक्षित करना चाहते हैं, तो कुछ महत्वपूर्ण प्रश्न हैं जिन्हें आपको खुद से पूछना चाहिए:
- क्या डेटा संवेदनशील है? आपको क्लाइंट पर कोई भी संवेदनशील डेटा संग्रहीत करने से बचना चाहिए, जैसे उपयोगकर्ता पासवर्ड।
- आपको इस डेटा को कितने समय तक रखना है? क्या आप इस डेटा को केवल वर्तमान सत्र के लिए एक्सेस करने की योजना बना रहे हैं या आप इसे हमेशा के लिए संग्रहीत करना चाहते हैं?
वेब ऐप के अंदर जानकारी संग्रहीत करने के कई तरीके हैं, इस पर निर्भर करता है कि आप क्या हासिल करना चाहते हैं। उदाहरण के लिए, आप एक सर्च क्वेरी को स्टोर करने के लिए URL का उपयोग कर सकते हैं और इसे उपयोगकर्ताओं के बीच साझा कर सकते हैं। यदि डेटा को सर्वर के साथ साझा करने की आवश्यकता है, जैसे प्रमाणीकरण जानकारी, तो आप HTTP कुकीज़ का उपयोग कर सकते हैं।
एक अन्य विकल्प डेटा संग्रहीत करने के लिए ब्राउज़र API में से एक का उपयोग करना है। इनमें से दो विशेष रूप से दिलचस्प हैं:
localStorage
: एक Key/Value स्टोर जो विभिन्न सत्रों में वर्तमान वेबसाइट के लिए विशिष्ट डेटा को संरक्षित करने की अनुमति देता है। इसमें संग्रहीत डेटा कभी समाप्त नहीं होता।sessionStorage
: यहlocalStorage
की तरह ही काम करता है, सिवाय इसके कि इसमें संग्रहीत डेटा सत्र समाप्त होने पर (जब ब्राउज़र बंद हो जाता है) साफ हो जाता है।
ध्यान दें कि ये दोनों API केवल strings को संग्रहीत करने की अनुमति देते हैं। यदि आप जटिल ऑब्जेक्ट संग्रहीत करना चाहते हैं, तो आपको इसे JSON प्रारूप में सीरियलाइज़ करना होगा, JSON.stringify()
का उपयोग करके।
✅ यदि आप एक वेब ऐप बनाना चाहते हैं जो सर्वर के साथ काम नहीं करता है, तो IndexedDB
API का उपयोग करके क्लाइंट पर एक डेटाबेस बनाना भी संभव है। यह उन्नत उपयोग मामलों के लिए या यदि आपको महत्वपूर्ण मात्रा में डेटा संग्रहीत करने की आवश्यकता है, तो आरक्षित है, क्योंकि इसका उपयोग करना अधिक जटिल है।
कार्य
हम चाहते हैं कि हमारे उपयोगकर्ता तब तक लॉग इन रहें जब तक वे स्पष्ट रूप से लॉगआउट बटन पर क्लिक न करें, इसलिए हम localStorage
का उपयोग करके अकाउंट डेटा को संग्रहीत करेंगे। सबसे पहले, आइए एक key को परिभाषित करें जिसका उपयोग हम अपने डेटा को संग्रहीत करने के लिए करेंगे।
const storageKey = 'savedAccount';
फिर updateState()
फंक्शन के अंत में यह लाइन जोड़ें:
localStorage.setItem(storageKey, JSON.stringify(state.account));
इसके साथ, उपयोगकर्ता अकाउंट डेटा संरक्षित रहेगा और हमेशा अपडेट रहेगा क्योंकि हमने पहले सभी स्टेट अपडेट को केंद्रीकृत किया था। यह वह जगह है जहां हम अपने पिछले रिफैक्टरिंग से लाभ उठाना शुरू करते हैं 🙂।
जैसा कि डेटा संग्रहीत किया गया है, हमें इसे ऐप लोड होने पर पुनर्स्थापित करने का भी ध्यान रखना होगा। चूंकि अब हमारे पास अधिक इनिशियलाइज़ेशन कोड होने लगेगा, इसलिए app.js
के नीचे हमारे पिछले कोड को भी शामिल करने के लिए एक नया init
फंक्शन बनाना एक अच्छा विचार हो सकता है:
function init() {
const savedAccount = localStorage.getItem(storageKey);
if (savedAccount) {
updateState('account', JSON.parse(savedAccount));
}
// Our previous initialization code
window.onpopstate = () => updateRoute();
updateRoute();
}
init();
यहां हम संग्रहीत डेटा को पुनः प्राप्त करते हैं, और यदि कोई डेटा है तो हम स्टेट को तदनुसार अपडेट करते हैं। इसे रूट अपडेट करने से पहले करना महत्वपूर्ण है, क्योंकि पेज अपडेट के दौरान स्टेट पर निर्भर कोड हो सकता है।
हम अपने एप्लिकेशन का डिफ़ॉल्ट पेज डैशबोर्ड पेज भी बना सकते हैं, क्योंकि अब हम अकाउंट डेटा को संरक्षित कर रहे हैं। यदि कोई डेटा नहीं मिलता है, तो डैशबोर्ड वैसे भी लॉगिन पेज पर रीडायरेक्ट करने का ध्यान रखता है। updateRoute()
में, फॉलबैक return navigate('/login');
को return navigate('/dashboard');
से बदलें।
अब ऐप में लॉगिन करें और पेज को रिफ्रेश करने का प्रयास करें। आपको डैशबोर्ड पर रहना चाहिए। इस अपडेट के साथ हमने अपनी सभी प्रारंभिक समस्याओं का ध्यान रखा है...
डेटा को रिफ्रेश करें
...लेकिन हमने शायद एक नई समस्या भी पैदा कर दी है। ओह!
test
अकाउंट का उपयोग करके डैशबोर्ड पर जाएं, फिर एक नया ट्रांजेक्शन बनाने के लिए टर्मिनल पर यह कमांड चलाएं:
curl --request POST \
--header "Content-Type: application/json" \
--data "{ \"date\": \"2020-07-24\", \"object\": \"Bought book\", \"amount\": -20 }" \
http://localhost:5000/api/accounts/test/transactions
अब ब्राउज़र में डैशबोर्ड पेज को रिफ्रेश करने का प्रयास करें। क्या होता है? क्या आप नया ट्रांजेक्शन देख सकते हैं?
स्टेट localStorage
के कारण अनिश्चित काल तक संरक्षित रहता है, लेकिन इसका मतलब यह भी है कि यह तब तक कभी अपडेट नहीं होता जब तक आप ऐप से लॉग आउट और फिर से लॉग इन नहीं करते!
इस समस्या को ठीक करने की एक संभावित रणनीति यह है कि डैशबोर्ड लोड होने पर हर बार अकाउंट डेटा को रीलोड किया जाए, ताकि पुराना डेटा न रहे।
कार्य
एक नया फंक्शन updateAccountData
बनाएं:
async function updateAccountData() {
const account = state.account;
if (!account) {
return logout();
}
const data = await getAccount(account.user);
if (data.error) {
return logout();
}
updateState('account', data);
}
यह मेथड जांचता है कि हम वर्तमान में लॉग इन हैं और फिर सर्वर से अकाउंट डेटा को रीलोड करता है।
refresh
नामक एक और फंक्शन बनाएं:
async function refresh() {
await updateAccountData();
updateDashboard();
}
यह अकाउंट डेटा को अपडेट करता है, फिर डैशबोर्ड पेज के HTML को अपडेट करने का ध्यान रखता है। यह वही है जिसे हमें डैशबोर्ड रूट लोड होने पर कॉल करना है। रूट डिफिनिशन को अपडेट करें:
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: refresh }
};
अब डैशबोर्ड को रीलोड करने का प्रयास करें, यह अपडेटेड अकाउंट डेटा प्रदर्शित करना चाहिए।
🚀 चुनौती
अब जब हम हर बार डैशबोर्ड लोड होने पर अकाउंट डेटा को रीलोड करते हैं, तो क्या आपको लगता है कि हमें सभी अकाउंट डेटा को संरक्षित करने की आवश्यकता है?
एक साथ काम करके यह बदलने का प्रयास करें कि localStorage
में क्या संग्रहीत और लोड किया गया है ताकि केवल वही शामिल हो जो ऐप को काम करने के लिए बिल्कुल आवश्यक है।
पोस्ट-लेक्चर क्विज़
असाइनमेंट
"Add transaction" डायलॉग लागू करें
असाइनमेंट पूरा करने के बाद यहां एक उदाहरण परिणाम है:
अस्वीकरण:
यह दस्तावेज़ AI अनुवाद सेवा Co-op Translator का उपयोग करके अनुवादित किया गया है। जबकि हम सटीकता के लिए प्रयासरत हैं, कृपया ध्यान दें कि स्वचालित अनुवाद में त्रुटियां या अशुद्धियां हो सकती हैं। मूल भाषा में उपलब्ध मूल दस्तावेज़ को प्रामाणिक स्रोत माना जाना चाहिए। महत्वपूर्ण जानकारी के लिए, पेशेवर मानव अनुवाद की सिफारिश की जाती है। इस अनुवाद के उपयोग से उत्पन्न किसी भी गलतफहमी या गलत व्याख्या के लिए हम उत्तरदायी नहीं हैं।