|
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()
का उपयोग करके किसी ऑब्जेक्ट का अपरिवर्तनीय संस्करण बना सकते हैं। यदि आप अपरिवर्तनीय ऑब्जेक्ट में परिवर्तन करने का प्रयास करते हैं, तो एक अपवाद उत्पन्न होगा।
✅ क्या आप जानते हैं कि शैलो और डीप अपरिवर्तनीय ऑब्जेक्ट में क्या अंतर है? आप इसके बारे में यहां पढ़ सकते हैं।
कार्य
एक नया 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
: एक की/वैल्यू स्टोर जो विभिन्न सत्रों में वर्तमान वेबसाइट के लिए विशिष्ट डेटा को संरक्षित करने की अनुमति देता है। इसमें संग्रहीत डेटा कभी समाप्त नहीं होता।sessionStorage
: यहlocalStorage
के समान काम करता है, सिवाय इसके कि इसमें संग्रहीत डेटा सत्र समाप्त होने पर (जब ब्राउज़र बंद हो जाता है) साफ हो जाता है।
ध्यान दें कि ये दोनों API केवल स्ट्रिंग्स को संग्रहीत करने की अनुमति देते हैं। यदि आप जटिल ऑब्जेक्ट संग्रहीत करना चाहते हैं, तो आपको इसे JSON प्रारूप में सीरियलाइज़ करना होगा, JSON.stringify()
का उपयोग करके।
✅ यदि आप एक ऐसा वेब ऐप बनाना चाहते हैं जो सर्वर के साथ काम न करे, तो IndexedDB
API का उपयोग करके क्लाइंट पर एक डेटाबेस बनाना भी संभव है। यह उन्नत उपयोग के मामलों के लिए आरक्षित है या यदि आपको बड़ी मात्रा में डेटा संग्रहीत करने की आवश्यकता है, क्योंकि इसका उपयोग करना अधिक जटिल है।
कार्य
हम चाहते हैं कि हमारे उपयोगकर्ता तब तक लॉग इन रहें जब तक वे स्पष्ट रूप से लॉगआउट बटन पर क्लिक न करें, इसलिए हम localStorage
का उपयोग करके खाता डेटा संग्रहीत करेंगे। पहले, आइए एक कुंजी परिभाषित करें जिसका उपयोग हम अपने डेटा को संग्रहीत करने के लिए करेंगे।
const storageKey = 'savedAccount';
फिर updateState()
फंक्शन के अंत में यह लाइन जोड़ें:
localStorage.setItem(storageKey, JSON.stringify(state.account));
इसके साथ, उपयोगकर्ता खाता डेटा संरक्षित रहेगा और हमेशा अपडेट रहेगा क्योंकि हमने पहले सभी स्टेट अपडेट को केंद्रीकृत किया था। यही वह जगह है जहां हम अपने पिछले सभी रिफैक्टरिंग का लाभ उठाना शुरू करते हैं 🙂।
चूंकि डेटा सहेजा गया है, हमें ऐप लोड होने पर इसे पुनर्स्थापित करने का भी ध्यान रखना होगा। चूंकि अब हमारे पास अधिक इनिशियलाइज़ेशन कोड होगा, इसलिए एक नया init
फंक्शन बनाना एक अच्छा विचार हो सकता है, जिसमें app.js
के नीचे हमारा पिछला कोड भी शामिल हो:
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
में संग्रहीत और लोड किए जाने वाले डेटा को केवल वही शामिल करने के लिए बदलने का प्रयास करें जो ऐप के काम करने के लिए बिल्कुल आवश्यक है।
पोस्ट-लेक्चर क्विज़
असाइनमेंट
लेन-देन जोड़ने का संवाद लागू करें
यहां एक उदाहरण परिणाम है जो असाइनमेंट पूरा करने के बाद दिखता है:
अस्वीकरण:
यह दस्तावेज़ AI अनुवाद सेवा Co-op Translator का उपयोग करके अनुवादित किया गया है। जबकि हम सटीकता सुनिश्चित करने का प्रयास करते हैं, कृपया ध्यान दें कि स्वचालित अनुवाद में त्रुटियां या अशुद्धियां हो सकती हैं। मूल भाषा में उपलब्ध मूल दस्तावेज़ को आधिकारिक स्रोत माना जाना चाहिए। महत्वपूर्ण जानकारी के लिए, पेशेवर मानव अनुवाद की सिफारिश की जाती है। इस अनुवाद के उपयोग से उत्पन्न किसी भी गलतफहमी या गलत व्याख्या के लिए हम उत्तरदायी नहीं हैं।