राज्य प्रबंधन एक वेब एप्लिकेशन का सबसे महत्वपूर्ण हिस्सा है। ग्लोबल वेरिएबल्स के उपयोग से लेकर रिएक्ट हुक्स तक, MobX, Redux या XState जैसे थर्ड-पार्टी लाइब्रेरीज़ के उपयोग से लेकर इन 3 के नाम तक, यह उन विषयों में से एक है जो सबसे अधिक चर्चाओं को बढ़ावा देता है क्योंकि इसे डिजाइन करने के लिए इसमें महारत हासिल करना महत्वपूर्ण है। विश्वसनीय और कुशल अनुप्रयोग।
आज, मैं वेधशालाओं की अवधारणा के आधार पर जावास्क्रिप्ट की 50 से कम लाइनों में एक मिनी राज्य प्रबंधन पुस्तकालय बनाने का प्रस्ताव करता हूं। इसे निश्चित रूप से छोटी परियोजनाओं के लिए उपयोग किया जा सकता है, लेकिन इस शैक्षिक अभ्यास से परे मैं अभी भी आपको अपनी वास्तविक परियोजनाओं के लिए अधिक मानकीकृत समाधानों की ओर रुख करने की सलाह देता हूं।
एक नई लाइब्रेरी परियोजना शुरू करते समय, तकनीकी कार्यान्वयन विवरण के बारे में सोचने से पहले इसकी अवधारणा को स्थिर करने और इसके विकास का मार्गदर्शन करने के लिए यह परिभाषित करना महत्वपूर्ण है कि इसकी एपीआई शुरुआत से कैसी दिख सकती है। एक वास्तविक परियोजना के लिए, लाइब्रेरी के कार्यान्वयन को मान्य करने के लिए इस समय परीक्षण लिखना शुरू करना भी संभव है क्योंकि यह टीडीडी दृष्टिकोण के अनुसार लिखा गया है।
यहां हम एक एकल वर्ग को निर्यात करना चाहते हैं जिसे हम राज्य कहेंगे जिसे प्रारंभिक स्थिति वाले ऑब्जेक्ट और एक एकल निरीक्षण विधि के साथ त्वरित किया जाएगा जो हमें पर्यवेक्षकों के साथ राज्य परिवर्तनों की सदस्यता लेने की अनुमति देता है। इन पर्यवेक्षकों को केवल तभी निष्पादित किया जाना चाहिए जब उनकी कोई निर्भरता बदल गई हो।
राज्य को बदलने के लिए, हम सेटस्टेट जैसी विधि के बजाय सीधे क्लास गुणों का उपयोग करना चाहते हैं।
चूंकि एक कोड स्निपेट एक हजार शब्दों के बराबर होता है, इसलिए हमारा अंतिम कार्यान्वयन उपयोग में कैसा दिख सकता है:
const state = new State({ count: 0, text: '', }); state.observe(({ count }) => { console.log('Count changed', count); }); state.observe(({ text }) => { console.log('Text changed', text); }); state.count = 1; state.text = 'Hello, world!'; state.count = 1; // Output: // Count changed 1 // Text changed Hello, world! // Count changed 2
आइए एक स्टेट क्लास बनाकर शुरुआत करें जो अपने कंस्ट्रक्टर में प्रारंभिक स्थिति को स्वीकार करता है और एक निरीक्षण विधि को उजागर करता है जिसे हम बाद में लागू करेंगे।
class State { constructor(initialState = {}) { this.state = initialState; this.observers = []; } observe(observer) { this.observers.push(observer); } }
यहां हम एक आंतरिक मध्यवर्ती राज्य ऑब्जेक्ट का उपयोग करना चुनते हैं जो हमें राज्य मूल्यों को बनाए रखने की अनुमति देगा। हम पर्यवेक्षकों को एक आंतरिक पर्यवेक्षक सरणी में भी संग्रहीत करते हैं जो इस कार्यान्वयन को पूरा करने पर उपयोगी होगा।
चूंकि इन 2 गुणों का उपयोग केवल इस वर्ग के अंदर किया जाएगा, हम उन्हें # के साथ उपसर्ग करके और वर्ग पर एक प्रारंभिक घोषणा जोड़कर थोड़ी वाक्यात्मक चीनी के साथ निजी घोषित कर सकते हैं:
class State { #state = {}; #observers = []; constructor(initialState = {}) { this.#state = initialState; this.#observers = []; } observe(observer) { this.#observers.push(observer); } }
सिद्धांत रूप में यह एक अच्छा अभ्यास होगा, लेकिन हम अगले चरण में प्रॉक्सी का उपयोग करेंगे और वे निजी संपत्तियों के साथ संगत नहीं हैं। विस्तार में जाए बिना और इस कार्यान्वयन को आसान बनाने के लिए, हम अभी सार्वजनिक संपत्तियों का उपयोग करेंगे।
जब हम इस परियोजना के लिए विशिष्टताओं की रूपरेखा तैयार करते हैं, तो हम राज्य मूल्यों को सीधे क्लास इंस्टेंस पर एक्सेस करना चाहते थे, न कि इसके आंतरिक राज्य ऑब्जेक्ट में प्रवेश के रूप में।
इसके लिए, हम एक प्रॉक्सी ऑब्जेक्ट का उपयोग करेंगे जो क्लास शुरू होने पर वापस आ जाएगा।
जैसा कि इसके नाम से पता चलता है, एक प्रॉक्सी आपको किसी ऑब्जेक्ट के लिए एक मध्यस्थ बनाने की अनुमति देता है, जो उसके गेटर्स और सेटर्स सहित कुछ ऑपरेशनों को रोकता है। हमारे मामले में, हम पहले गेटर को उजागर करते हुए एक प्रॉक्सी बनाते हैं जो हमें राज्य ऑब्जेक्ट के इनपुट को उजागर करने की अनुमति देता है जैसे कि वे सीधे राज्य उदाहरण से संबंधित हों।
class State { constructor(initialState = {}) { this.state = initialState; this.observers = []; return new Proxy(this, { get: (target, prop) => { if (prop in target.state) { return target.state[prop]; } return target[prop]; }, }); } observe(observer) { this.observers.push(observer); } } const state = new State({ count: 0, text: '', }); console.log(state.count); // 0
अब हम स्टेट को इंस्टेंट करते समय एक प्रारंभिक स्टेट ऑब्जेक्ट को परिभाषित कर सकते हैं और फिर सीधे उस इंस्टेंस से उसके मान प्राप्त कर सकते हैं। अब आइए देखें कि इसके डेटा में हेरफेर कैसे किया जाए।
हमने एक गेटर जोड़ा है, इसलिए अगला तार्किक कदम एक सेटर जोड़ना है जो हमें राज्य ऑब्जेक्ट में हेरफेर करने की अनुमति देता है।
हम पहले जांचते हैं कि कुंजी इस ऑब्जेक्ट से संबंधित है, फिर जांचते हैं कि अनावश्यक अपडेट को रोकने के लिए मान वास्तव में बदल गया है, और अंत में ऑब्जेक्ट को नए मान के साथ अपडेट करते हैं।
class State { constructor(initialState = {}) { this.state = initialState; this.observers = []; return new Proxy(this, { get: (target, prop) => { if (prop in target.state) { return target.state[prop]; } return target[prop]; }, set: (target, prop, value) => { if (prop in target.state) { if (target.state[prop] !== value) { target.state[prop] = value; } } else { target[prop] = value; } }, }); } observe(observer) { this.observers.push(observer); } } const state = new State({ count: 0, text: '', }); console.log(state.count); // 0 state.count = 1; console.log(state.count); // 1
अब हमने डेटा पढ़ने और लिखने का काम पूरा कर लिया है। हम राज्य मान बदल सकते हैं और फिर उस परिवर्तन को पुनः प्राप्त कर सकते हैं। अब तक हमारा कार्यान्वयन बहुत उपयोगी नहीं है, तो चलिए अब पर्यवेक्षकों को लागू करते हैं।
हमारे पास पहले से ही एक सरणी है जिसमें हमारे उदाहरण पर घोषित पर्यवेक्षक फ़ंक्शन शामिल हैं, इसलिए जब भी कोई मान बदलता है तो हमें बस उन्हें एक-एक करके कॉल करना होगा।
class State { constructor(initialState = {}) { this.state = initialState; this.observers = []; return new Proxy(this, { get: (target, prop) => { if (prop in target.state) { return target.state[prop]; } return target[prop]; }, set: (target, prop, value) => { if (prop in target.state) { if (target.state[prop] !== value) { target.state[prop] = value; this.observers.forEach((observer) => { observer(this.state); }); } } else { target[prop] = value; } }, }); } observe(observer) { this.observers.push(observer); } } const state = new State({ count: 0, text: '', }); state.observe(({ count }) => { console.log('Count changed', count); }); state.observe(({ text }) => { console.log('Text changed', text); }); state.count = 1; state.text = 'Hello, world!'; // Output: // Count changed 1 // Text changed // Count changed 1 // Text changed Hello, world!
बहुत बढ़िया, अब हम डेटा परिवर्तनों पर प्रतिक्रिया दे रहे हैं!
यद्यपि छोटी समस्या है। यदि आप अब तक ध्यान दे रहे हैं, तो हम मूल रूप से पर्यवेक्षकों को तभी चलाना चाहते थे जब उनकी कोई निर्भरता बदल गई हो। हालाँकि, यदि हम इस कोड को चलाते हैं तो हम देखते हैं कि प्रत्येक पर्यवेक्षक हर बार राज्य का एक हिस्सा बदलने पर चलता है।
लेकिन फिर हम इन कार्यों की निर्भरता की पहचान कैसे कर सकते हैं?
एक बार फिर, प्रॉक्सी हमारे बचाव में आए हैं। अपने पर्यवेक्षक कार्यों की निर्भरता की पहचान करने के लिए, हम अपने राज्य ऑब्जेक्ट का एक प्रॉक्सी बना सकते हैं, उन्हें एक तर्क के रूप में चला सकते हैं, और नोट कर सकते हैं कि उन्होंने किन गुणों तक पहुंच बनाई है।
सरल, लेकिन प्रभावी।
पर्यवेक्षकों को बुलाते समय, हमें बस यह जांचना है कि क्या उनकी अद्यतन संपत्ति पर निर्भरता है और यदि ऐसा है तो ही उन्हें ट्रिगर करें।
इस अंतिम भाग को जोड़कर यहां हमारी मिनी-लाइब्रेरी का अंतिम कार्यान्वयन है। आप देखेंगे कि पर्यवेक्षकों की सरणी में अब प्रत्येक पर्यवेक्षक की निर्भरता को बनाए रखने की अनुमति देने वाली वस्तुएं शामिल हैं।
class State { constructor(initialState = {}) { this.state = initialState; this.observers = []; return new Proxy(this, { get: (target, prop) => { if (prop in target.state) { return target.state[prop]; } return target[prop]; }, set: (target, prop, value) => { if (prop in target.state) { if (target.state[prop] !== value) { target.state[prop] = value; this.observers.forEach(({ observer, dependencies }) => { if (dependencies.has(prop)) { observer(this.state); } }); } } else { target[prop] = value; } }, }); } observe(observer) { const dependencies = new Set(); const proxy = new Proxy(this.state, { get: (target, prop) => { dependencies.add(prop); return target[prop]; }, }); observer(proxy); this.observers.push({ observer, dependencies }); } } const state = new State({ count: 0, text: '', }); state.observe(({ count }) => { console.log('Count changed', count); }); state.observe(({ text }) => { console.log('Text changed', text); }); state.observe((state) => { console.log('Count or text changed', state.count, state.text); }); state.count = 1; state.text = 'Hello, world!'; state.count = 1; // Output: // Count changed 0 // Text changed // Count or text changed 0 // Count changed 1 // Count or text changed 1 // Text changed Hello, world! // Count or text changed 1 Hello, world! // Count changed 2 // Count or text changed 2 Hello, world!
और यह आपके पास है, कोड की 45 पंक्तियों में हमने जावास्क्रिप्ट में एक मिनी स्टेट प्रबंधन लाइब्रेरी लागू की है।
यदि हम आगे जाना चाहते हैं, तो हम राज्य उदाहरण के गुणों पर सुझाव प्राप्त करने के लिए JSDoc के साथ टाइप सुझाव जोड़ सकते हैं या टाइपस्क्रिप्ट में इसे फिर से लिख सकते हैं।
हम एक अनऑब्जर्व विधि भी जोड़ सकते हैं जो स्टेट.ऑब्जर्व द्वारा लौटाए गए ऑब्जेक्ट पर प्रदर्शित होगी।
सेटर व्यवहार को सेटस्टेट विधि में अमूर्त करना भी उपयोगी हो सकता है जो हमें एक साथ कई गुणों को संशोधित करने की अनुमति देता है। वर्तमान में, हमें अपने राज्य की प्रत्येक संपत्ति को एक-एक करके संशोधित करना होगा, जिससे कई पर्यवेक्षकों को ट्रिगर किया जा सकता है यदि उनमें से कुछ निर्भरता साझा करते हैं।
किसी भी मामले में, मुझे आशा है कि आपने इस छोटे से अभ्यास का उतना ही आनंद लिया जितना मैंने लिया और इसने आपको जावास्क्रिप्ट में प्रॉक्सी की अवधारणा को थोड़ा और गहराई से समझने की अनुमति दी।
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3