You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
32 KiB
292 lines
32 KiB
<!--
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
{
|
|
"original_hash": "4fa20c513e367e9cdd401bf49ae16e33",
|
|
"translation_date": "2025-08-24T13:46:40+00:00",
|
|
"source_file": "7-bank-project/4-state-management/README.md",
|
|
"language_code": "hi"
|
|
}
|
|
-->
|
|
# बैंकिंग ऐप बनाएं भाग 4: स्टेट मैनेजमेंट की अवधारणाएँ
|
|
|
|
## प्री-लेक्चर क्विज़
|
|
|
|
[प्री-लेक्चर क्विज़](https://ff-quizzes.netlify.app/web/quiz/47)
|
|
|
|
### परिचय
|
|
|
|
जैसे-जैसे एक वेब एप्लिकेशन बढ़ता है, डेटा प्रवाह को ट्रैक करना चुनौतीपूर्ण हो जाता है। कौन सा कोड डेटा प्राप्त करता है, कौन सा पेज इसे उपयोग करता है, इसे कब और कहाँ अपडेट करने की आवश्यकता है... यह आसानी से गड़बड़ कोड में बदल सकता है जिसे बनाए रखना मुश्किल है। यह विशेष रूप से तब सच है जब आपको अपने ऐप के विभिन्न पेजों के बीच डेटा साझा करने की आवश्यकता होती है, जैसे उपयोगकर्ता डेटा। *स्टेट मैनेजमेंट* की अवधारणा हमेशा सभी प्रकार के प्रोग्रामों में मौजूद रही है, लेकिन जैसे-जैसे वेब ऐप्स की जटिलता बढ़ती जा रही है, यह अब विकास के दौरान विचार करने का एक प्रमुख बिंदु बन गया है।
|
|
|
|
इस अंतिम भाग में, हम उस ऐप पर विचार करेंगे जिसे हमने बनाया है ताकि स्टेट को बेहतर तरीके से प्रबंधित किया जा सके, जिससे ब्राउज़र को किसी भी समय रिफ्रेश करने का समर्थन मिले और उपयोगकर्ता सत्रों के बीच डेटा को बनाए रखा जा सके।
|
|
|
|
### पूर्वापेक्षा
|
|
|
|
आपको इस पाठ के लिए वेब ऐप के [डेटा फेचिंग](../3-data/README.md) भाग को पूरा करना होगा। आपको [Node.js](https://nodejs.org) इंस्टॉल करना होगा और [सर्वर API](../api/README.md) को लोकल रूप से चलाना होगा ताकि आप अकाउंट डेटा प्रबंधित कर सकें।
|
|
|
|
आप यह कमांड टर्मिनल में चलाकर जांच सकते हैं कि सर्वर सही तरीके से चल रहा है:
|
|
|
|
```sh
|
|
curl http://localhost:5000/api
|
|
# -> should return "Bank API v1.0.0" as a result
|
|
```
|
|
|
|
---
|
|
|
|
## स्टेट मैनेजमेंट पर पुनर्विचार
|
|
|
|
[पिछले पाठ](../3-data/README.md) में, हमने अपने ऐप में स्टेट की एक बुनियादी अवधारणा पेश की थी जिसमें `account` नामक एक ग्लोबल वेरिएबल था जो वर्तमान में लॉग इन किए गए उपयोगकर्ता के बैंक डेटा को संग्रहीत करता है। हालांकि, हमारे वर्तमान कार्यान्वयन में कुछ खामियां हैं। डैशबोर्ड पर रहते हुए पेज को रिफ्रेश करने का प्रयास करें। क्या होता है?
|
|
|
|
वर्तमान कोड में 3 समस्याएं हैं:
|
|
|
|
- स्टेट संरक्षित नहीं है, क्योंकि ब्राउज़र रिफ्रेश आपको लॉगिन पेज पर वापस ले जाता है।
|
|
- स्टेट को संशोधित करने वाले कई फंक्शन हैं। जैसे-जैसे ऐप बढ़ता है, यह परिवर्तनों को ट्रैक करना मुश्किल बना सकता है और एक को अपडेट करना भूलना आसान हो जाता है।
|
|
- स्टेट साफ नहीं किया गया है, इसलिए जब आप *लॉगआउट* पर क्लिक करते हैं तो अकाउंट डेटा अभी भी वहां होता है, भले ही आप लॉगिन पेज पर हों।
|
|
|
|
हम इन समस्याओं को एक-एक करके हल करने के लिए अपने कोड को अपडेट कर सकते हैं, लेकिन इससे कोड का अधिक डुप्लीकेशन होगा और ऐप अधिक जटिल और बनाए रखने में कठिन हो जाएगा। या हम कुछ मिनटों के लिए रुक सकते हैं और अपनी रणनीति पर पुनर्विचार कर सकते हैं।
|
|
|
|
> हम वास्तव में यहां कौन सी समस्याओं को हल करने की कोशिश कर रहे हैं?
|
|
|
|
[स्टेट मैनेजमेंट](https://en.wikipedia.org/wiki/State_management) का उद्देश्य इन दो विशेष समस्याओं को हल करने के लिए एक अच्छा दृष्टिकोण खोजना है:
|
|
|
|
- ऐप में डेटा प्रवाह को समझने योग्य कैसे रखें?
|
|
- स्टेट डेटा को हमेशा उपयोगकर्ता इंटरफ़ेस के साथ (और इसके विपरीत) सिंक में कैसे रखें?
|
|
|
|
एक बार जब आप इनका ध्यान रख लेते हैं, तो आपके पास जो अन्य समस्याएं हो सकती हैं, वे या तो पहले ही हल हो चुकी होंगी या उन्हें हल करना आसान हो गया होगा। इन समस्याओं को हल करने के लिए कई संभावित दृष्टिकोण हैं, लेकिन हम एक सामान्य समाधान के साथ जाएंगे जिसमें **डेटा और इसे बदलने के तरीकों को केंद्रीकृत करना** शामिल है। डेटा प्रवाह इस प्रकार होगा:
|
|
|
|

|
|
|
|
> हम यहां उस हिस्से को कवर नहीं करेंगे जहां डेटा स्वचालित रूप से व्यू अपडेट को ट्रिगर करता है, क्योंकि यह [रिएक्टिव प्रोग्रामिंग](https://en.wikipedia.org/wiki/Reactive_programming) की अधिक उन्नत अवधारणाओं से जुड़ा हुआ है। यदि आप गहराई से अध्ययन करने के इच्छुक हैं, तो यह एक अच्छा विषय है।
|
|
|
|
✅ स्टेट मैनेजमेंट के लिए कई लाइब्रेरी उपलब्ध हैं, जिनमें [Redux](https://redux.js.org) एक लोकप्रिय विकल्प है। इसके उपयोग किए गए अवधारणाओं और पैटर्न को देखें क्योंकि यह अक्सर यह समझने का एक अच्छा तरीका होता है कि बड़े वेब ऐप्स में आप किन संभावित समस्याओं का सामना कर सकते हैं और उन्हें कैसे हल किया जा सकता है।
|
|
|
|
### कार्य
|
|
|
|
हम थोड़ा रिफैक्टरिंग से शुरुआत करेंगे। `account` डिक्लेरेशन को बदलें:
|
|
|
|
```js
|
|
let account = null;
|
|
```
|
|
|
|
से:
|
|
|
|
```js
|
|
let state = {
|
|
account: null
|
|
};
|
|
```
|
|
|
|
यह विचार हमारे ऐप डेटा को एक सिंगल स्टेट ऑब्जेक्ट में *केंद्रीकृत* करने का है। फिलहाल हमारे पास स्टेट में केवल `account` है, इसलिए यह ज्यादा नहीं बदलता है, लेकिन यह विकास के लिए एक रास्ता बनाता है।
|
|
|
|
हमें इसका उपयोग करने वाले फंक्शन को भी अपडेट करना होगा। `register()` और `login()` फंक्शन में, `account = ...` को `state.account = ...` से बदलें;
|
|
|
|
`updateDashboard()` फंक्शन के शीर्ष पर, यह लाइन जोड़ें:
|
|
|
|
```js
|
|
const account = state.account;
|
|
```
|
|
|
|
यह रिफैक्टरिंग अपने आप में बहुत सुधार नहीं लाती है, लेकिन विचार अगले परिवर्तनों के लिए नींव रखना था।
|
|
|
|
## डेटा परिवर्तनों को ट्रैक करें
|
|
|
|
अब जब हमने अपना डेटा स्टोर करने के लिए `state` ऑब्जेक्ट स्थापित कर लिया है, तो अगला कदम अपडेट को केंद्रीकृत करना है। लक्ष्य यह है कि किसी भी परिवर्तन और उनके होने के समय को ट्रैक करना आसान हो जाए।
|
|
|
|
`state` ऑब्जेक्ट में परिवर्तन करने से बचने के लिए, इसे [*immutable*](https://en.wikipedia.org/wiki/Immutable_object) मानना भी एक अच्छा अभ्यास है, जिसका अर्थ है कि इसे बिल्कुल भी संशोधित नहीं किया जा सकता। इसका मतलब यह भी है कि यदि आप इसमें कुछ भी बदलना चाहते हैं तो आपको एक नया स्टेट ऑब्जेक्ट बनाना होगा। ऐसा करके, आप संभावित अवांछित [साइड इफेक्ट्स](https://en.wikipedia.org/wiki/Side_effect_(computer_science)) के बारे में सुरक्षा बनाते हैं और अपने ऐप में नई सुविधाओं को लागू करने जैसे कि undo/redo को सक्षम करने की संभावनाओं को खोलते हैं, साथ ही इसे डिबग करना आसान बनाते हैं। उदाहरण के लिए, आप स्टेट में किए गए हर बदलाव को लॉग कर सकते हैं और बग के स्रोत को समझने के लिए परिवर्तनों का इतिहास रख सकते हैं।
|
|
|
|
जावास्क्रिप्ट में, आप [`Object.freeze()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) का उपयोग करके ऑब्जेक्ट का एक immutable संस्करण बना सकते हैं। यदि आप immutable ऑब्जेक्ट में परिवर्तन करने का प्रयास करते हैं, तो एक अपवाद उत्पन्न होगा।
|
|
|
|
✅ क्या आप जानते हैं कि *shallow* और *deep* immutable ऑब्जेक्ट में क्या अंतर है? आप इसके बारे में [यहां](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#What_is_shallow_freeze) पढ़ सकते हैं।
|
|
|
|
### कार्य
|
|
|
|
आइए एक नया `updateState()` फंक्शन बनाएं:
|
|
|
|
```js
|
|
function updateState(property, newData) {
|
|
state = Object.freeze({
|
|
...state,
|
|
[property]: newData
|
|
});
|
|
}
|
|
```
|
|
|
|
इस फंक्शन में, हम एक नया स्टेट ऑब्जेक्ट बना रहे हैं और पिछले स्टेट से डेटा को [*स्प्रेड (`...`) ऑपरेटर*](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals) का उपयोग करके कॉपी कर रहे हैं। फिर हम [ब्रैकेट नोटेशन](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Working_with_Objects#Objects_and_properties) `[property]` का उपयोग करके स्टेट ऑब्जेक्ट की एक विशेष प्रॉपर्टी को नए डेटा के साथ ओवरराइड करते हैं। अंत में, हम `Object.freeze()` का उपयोग करके ऑब्जेक्ट को लॉक कर देते हैं ताकि संशोधन रोके जा सकें। फिलहाल हमारे स्टेट में केवल `account` प्रॉपर्टी संग्रहीत है, लेकिन इस दृष्टिकोण के साथ आप स्टेट में जितनी चाहें उतनी प्रॉपर्टी जोड़ सकते हैं।
|
|
|
|
हम यह सुनिश्चित करने के लिए `state` इनिशियलाइज़ेशन को भी अपडेट करेंगे कि प्रारंभिक स्टेट भी फ्रीज हो:
|
|
|
|
```js
|
|
let state = Object.freeze({
|
|
account: null
|
|
});
|
|
```
|
|
|
|
इसके बाद, `register` फंक्शन को अपडेट करें और `state.account = result;` असाइनमेंट को बदलें:
|
|
|
|
```js
|
|
updateState('account', result);
|
|
```
|
|
|
|
`login` फंक्शन के साथ भी ऐसा ही करें, `state.account = data;` को बदलें:
|
|
|
|
```js
|
|
updateState('account', data);
|
|
```
|
|
|
|
अब हम उपयोगकर्ता द्वारा *लॉगआउट* पर क्लिक करने पर अकाउंट डेटा साफ न होने की समस्या को ठीक करने का अवसर लेंगे।
|
|
|
|
एक नया फंक्शन `logout()` बनाएं:
|
|
|
|
```js
|
|
function logout() {
|
|
updateState('account', null);
|
|
navigate('/login');
|
|
}
|
|
```
|
|
|
|
`updateDashboard()` में, रीडायरेक्शन `return navigate('/login');` को `return logout();` से बदलें;
|
|
|
|
एक नया अकाउंट रजिस्टर करें, लॉगआउट करें और फिर से लॉगिन करें यह जांचने के लिए कि सब कुछ अभी भी सही तरीके से काम कर रहा है।
|
|
|
|
> टिप: आप ब्राउज़र के डेवलपमेंट टूल्स में कंसोल खोलकर और `updateState()` के नीचे `console.log(state)` जोड़कर सभी स्टेट परिवर्तनों को देख सकते हैं।
|
|
|
|
## स्टेट को संरक्षित करें
|
|
|
|
अधिकांश वेब ऐप्स को सही तरीके से काम करने के लिए डेटा को संरक्षित करने की आवश्यकता होती है। सभी महत्वपूर्ण डेटा आमतौर पर डेटाबेस में संग्रहीत होते हैं और सर्वर API के माध्यम से एक्सेस किए जाते हैं, जैसे कि हमारे मामले में उपयोगकर्ता अकाउंट डेटा। लेकिन कभी-कभी, उपयोगकर्ता अनुभव को बेहतर बनाने या लोडिंग प्रदर्शन में सुधार करने के लिए ब्राउज़र में चल रहे क्लाइंट ऐप पर कुछ डेटा संरक्षित करना भी दिलचस्प होता है।
|
|
|
|
जब आप अपने ब्राउज़र में डेटा संरक्षित करना चाहते हैं, तो कुछ महत्वपूर्ण प्रश्न हैं जिन्हें आपको खुद से पूछना चाहिए:
|
|
|
|
- *क्या डेटा संवेदनशील है?* आपको क्लाइंट पर कोई भी संवेदनशील डेटा संग्रहीत करने से बचना चाहिए, जैसे उपयोगकर्ता पासवर्ड।
|
|
- *आपको इस डेटा को कितने समय तक रखना है?* क्या आप इस डेटा को केवल वर्तमान सत्र के लिए एक्सेस करने की योजना बना रहे हैं या आप इसे हमेशा के लिए संग्रहीत करना चाहते हैं?
|
|
|
|
वेब ऐप के अंदर जानकारी संग्रहीत करने के कई तरीके हैं, इस पर निर्भर करता है कि आप क्या हासिल करना चाहते हैं। उदाहरण के लिए, आप एक सर्च क्वेरी को स्टोर करने के लिए URL का उपयोग कर सकते हैं और इसे उपयोगकर्ताओं के बीच साझा कर सकते हैं। यदि डेटा को सर्वर के साथ साझा करने की आवश्यकता है, जैसे [प्रमाणीकरण](https://en.wikipedia.org/wiki/Authentication) जानकारी, तो आप [HTTP कुकीज़](https://developer.mozilla.org/docs/Web/HTTP/Cookies) का उपयोग कर सकते हैं।
|
|
|
|
एक अन्य विकल्प डेटा संग्रहीत करने के लिए ब्राउज़र API में से एक का उपयोग करना है। इनमें से दो विशेष रूप से दिलचस्प हैं:
|
|
|
|
- [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage): एक [Key/Value स्टोर](https://en.wikipedia.org/wiki/Key%E2%80%93value_database) जो विभिन्न सत्रों में वर्तमान वेबसाइट के लिए विशिष्ट डेटा को संरक्षित करने की अनुमति देता है। इसमें संग्रहीत डेटा कभी समाप्त नहीं होता।
|
|
- [`sessionStorage`](https://developer.mozilla.org/docs/Web/API/Window/sessionStorage): यह `localStorage` की तरह ही काम करता है, सिवाय इसके कि इसमें संग्रहीत डेटा सत्र समाप्त होने पर (जब ब्राउज़र बंद हो जाता है) साफ हो जाता है।
|
|
|
|
ध्यान दें कि ये दोनों API केवल [strings](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) को संग्रहीत करने की अनुमति देते हैं। यदि आप जटिल ऑब्जेक्ट संग्रहीत करना चाहते हैं, तो आपको इसे [JSON](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON) प्रारूप में सीरियलाइज़ करना होगा, [`JSON.stringify()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) का उपयोग करके।
|
|
|
|
✅ यदि आप एक वेब ऐप बनाना चाहते हैं जो सर्वर के साथ काम नहीं करता है, तो [`IndexedDB` API](https://developer.mozilla.org/docs/Web/API/IndexedDB_API) का उपयोग करके क्लाइंट पर एक डेटाबेस बनाना भी संभव है। यह उन्नत उपयोग मामलों के लिए या यदि आपको महत्वपूर्ण मात्रा में डेटा संग्रहीत करने की आवश्यकता है, तो आरक्षित है, क्योंकि इसका उपयोग करना अधिक जटिल है।
|
|
|
|
### कार्य
|
|
|
|
हम चाहते हैं कि हमारे उपयोगकर्ता तब तक लॉग इन रहें जब तक वे स्पष्ट रूप से *लॉगआउट* बटन पर क्लिक न करें, इसलिए हम `localStorage` का उपयोग करके अकाउंट डेटा को संग्रहीत करेंगे। सबसे पहले, आइए एक key को परिभाषित करें जिसका उपयोग हम अपने डेटा को संग्रहीत करने के लिए करेंगे।
|
|
|
|
```js
|
|
const storageKey = 'savedAccount';
|
|
```
|
|
|
|
फिर `updateState()` फंक्शन के अंत में यह लाइन जोड़ें:
|
|
|
|
```js
|
|
localStorage.setItem(storageKey, JSON.stringify(state.account));
|
|
```
|
|
|
|
इसके साथ, उपयोगकर्ता अकाउंट डेटा संरक्षित रहेगा और हमेशा अपडेट रहेगा क्योंकि हमने पहले सभी स्टेट अपडेट को केंद्रीकृत किया था। यह वह जगह है जहां हम अपने पिछले रिफैक्टरिंग से लाभ उठाना शुरू करते हैं 🙂।
|
|
|
|
जैसा कि डेटा संग्रहीत किया गया है, हमें इसे ऐप लोड होने पर पुनर्स्थापित करने का भी ध्यान रखना होगा। चूंकि अब हमारे पास अधिक इनिशियलाइज़ेशन कोड होने लगेगा, इसलिए `app.js` के नीचे हमारे पिछले कोड को भी शामिल करने के लिए एक नया `init` फंक्शन बनाना एक अच्छा विचार हो सकता है:
|
|
|
|
```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` अकाउंट का उपयोग करके डैशबोर्ड पर जाएं, फिर एक नया ट्रांजेक्शन बनाने के लिए टर्मिनल पर यह कमांड चलाएं:
|
|
|
|
```sh
|
|
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` बनाएं:
|
|
|
|
```js
|
|
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` नामक एक और फंक्शन बनाएं:
|
|
|
|
```js
|
|
async function refresh() {
|
|
await updateAccountData();
|
|
updateDashboard();
|
|
}
|
|
```
|
|
|
|
यह अकाउंट डेटा को अपडेट करता है, फिर डैशबोर्ड पेज के HTML को अपडेट करने का ध्यान रखता है। यह वही है जिसे हमें डैशबोर्ड रूट लोड होने पर कॉल करना है। रूट डिफिनिशन को अपडेट करें:
|
|
|
|
```js
|
|
const routes = {
|
|
'/login': { templateId: 'login' },
|
|
'/dashboard': { templateId: 'dashboard', init: refresh }
|
|
};
|
|
```
|
|
|
|
अब डैशबोर्ड को रीलोड करने का प्रयास करें, यह अपडेटेड अकाउंट डेटा प्रदर्शित करना चाहिए।
|
|
|
|
---
|
|
|
|
## 🚀 चुनौती
|
|
|
|
अब जब हम हर बार डैशबोर्ड लोड होने पर अकाउंट डेटा को रीलोड करते हैं, तो क्या आपको लगता है कि हमें *सभी अकाउंट* डेटा को संरक्षित करने की आवश्यकता है?
|
|
|
|
एक साथ काम करके यह बदलने का प्रयास करें कि `localStorage` में क्या संग्रहीत और लोड किया गया है ताकि केवल वही शामिल हो जो ऐप को काम करने के लिए बिल्कुल आवश्यक है।
|
|
|
|
## पोस्ट-लेक्चर क्विज़
|
|
[पोस्ट-लेक्चर क्विज़](https://ff-quizzes.netlify.app/web/quiz/48)
|
|
|
|
## असाइनमेंट
|
|
|
|
["Add transaction" डायलॉग लागू करें](assignment.md)
|
|
|
|
असाइनमेंट पूरा करने के बाद यहां एक उदाहरण परिणाम है:
|
|
|
|

|
|
|
|
**अस्वीकरण**:
|
|
यह दस्तावेज़ AI अनुवाद सेवा [Co-op Translator](https://github.com/Azure/co-op-translator) का उपयोग करके अनुवादित किया गया है। जबकि हम सटीकता के लिए प्रयासरत हैं, कृपया ध्यान दें कि स्वचालित अनुवाद में त्रुटियां या अशुद्धियां हो सकती हैं। मूल भाषा में उपलब्ध मूल दस्तावेज़ को प्रामाणिक स्रोत माना जाना चाहिए। महत्वपूर्ण जानकारी के लिए, पेशेवर मानव अनुवाद की सिफारिश की जाती है। इस अनुवाद के उपयोग से उत्पन्न किसी भी गलतफहमी या गलत व्याख्या के लिए हम उत्तरदायी नहीं हैं। |