रिएक्ट के हुड के तहत। हम अपने कार्यान्वयन को खरोंच से लिखते हैं

लेखों की इस श्रृंखला में, हम स्क्रैच से अपना स्वयं का रिएक्ट कार्यान्वयन बनाएंगे। अंत में, आपको इस बात की समझ होगी कि रिएक्ट कैसे काम करता है, घटक जीवन चक्र के कौन से तरीके इसे कहते हैं, और क्यों। यह लेख उन लोगों के लिए है जो पहले ही रिएक्ट का उपयोग कर चुके हैं और इसके उपकरण के बारे में सीखना चाहते हैं, या बहुत उत्सुक हैं।

छवि

यह लेख रिएक्ट इंटरनेशनल, पार्ट वन: मूल प्रतिपादन का अनुवाद है

यह वास्तव में पाँच में से पहला लेख है


  1. रेंडरिंग बेसिक्स <- हम यहां हैं
  2. ComponentWillMount और ComponentsDidMount
  3. अद्यतन
  4. setState
  5. लेन-देन

जब रिएक्ट 15.3 प्रासंगिक था, विशेष रूप से रिएक्टडॉम और स्टैक रिसीलर के उपयोग से सामग्री बनाई गई थी। प्रतिक्रिया 16 और इसके बाद के संस्करण में कुछ बदलाव हैं। हालांकि, यह सामग्री प्रासंगिक बनी हुई है, क्योंकि यह "हुड के तहत" क्या हो रहा है, इसका एक सामान्य विचार देता है।

भाग 1. मूल बातें प्रतिपादन


तत्वों और घटकों


प्रतिक्रिया में तीन प्रकार की संस्थाएँ हैं: एक देशी DOM तत्व, एक आभासी प्रतिक्रिया तत्व और एक घटक।

मूल डोम तत्व


ये DOM तत्व हैं जो ब्राउज़र वेब पेज बनाने के लिए उपयोग करता है, उदाहरण के लिए, div, span, h1। React उन्हें document.createElement () कॉल करके बनाता है, और ब्राउज़र के साथ ब्राउज़र आधारित DOM API तरीकों जैसे element.insertBefore (), element.nodeValue, और अन्य का उपयोग करके पृष्ठ के साथ इंटरैक्ट करता है।

आभासी प्रतिक्रिया तत्व


एक आभासी प्रतिक्रिया तत्व (जिसे अक्सर "तत्व" के रूप में संदर्भित किया जाता है) एक जावास्क्रिप्ट ऑब्जेक्ट है जिसमें एक मूल डोम तत्व या ऐसे तत्वों के पेड़ को बनाने या अपडेट करने के लिए आवश्यक गुण होते हैं। वर्चुअल रिएक्ट तत्व के आधार पर, देशी डोम तत्व बनाए जाते हैं, जैसे डिव, स्पैन, एच 1 और अन्य। हम कह सकते हैं कि एक वर्चुअल रिएक्ट तत्व उपयोगकर्ता परिभाषित कंपोजिट घटक का एक उदाहरण है, इसके बारे में और नीचे।

अंग


घटक प्रतिक्रिया में एक काफी सामान्य शब्द है। घटक ऐसी संस्थाएँ हैं जिनके साथ प्रतिक्रिया विभिन्न जोड़तोड़ करती है। विभिन्न घटक विभिन्न उद्देश्यों की पूर्ति करते हैं। उदाहरण के लिए, ReactDom लाइब्रेरी से ReactDomComponent रिएक्ट तत्वों और उनके संबंधित डोम डोम तत्वों के बीच लिंक करने के लिए जिम्मेदार है।

कस्टम यौगिक घटक


सबसे अधिक संभावना है कि आप पहले से ही इस प्रकार के घटक का सामना कर चुके हैं। जब आप React.createClass कहते हैं () या फिर React.Component के माध्यम से ES6 कक्षाओं का उपयोग करते हैं, तो आप एक कस्टम कंपोजिट घटक बनाते हैं। इस तरह के एक घटक में जीवनचक्र की विधियाँ होती हैं, जैसे कि घटकवैलमाउंट, शो कॉंपोनेंट यूपीडेट और अन्य। हम उन्हें किसी प्रकार के तर्क को जोड़ने के लिए पुनर्परिभाषित कर सकते हैं। इसके अलावा, अन्य तरीके बनाए जाते हैं, जैसे कि माउंटकंपोनेंट, प्राप्तकंपोनेंट। इन तरीकों का उपयोग केवल React द्वारा इसके आंतरिक उद्देश्यों के लिए किया जाता है, हम किसी भी तरह से उनके साथ बातचीत नहीं करते हैं।

ज़नूदामोड = पर
वास्तव में, उपयोगकर्ता-निर्मित घटक शुरू में पूर्ण नहीं होते हैं। React उन्हें एक ReactCompositeComponentWrapper में लपेटता है, जो हमारे घटकों में सभी जीवन चक्र विधियों को जोड़ता है, जिसके बाद React उन्हें (सम्मिलित करें, अपडेट, आदि) प्रबंधित कर सकता है।

प्रतिक्रियात्मक घोषणा


जब कस्टम घटकों की बात आती है, तो हमारा कार्य इन घटकों की कक्षाओं को परिभाषित करना है, लेकिन हम इन कक्षाओं को तुरंत नहीं करते हैं। जरूरत पड़ने पर रिएक्ट उन्हें बनाता है।

इसके अलावा, हम स्पष्ट रूप से एक अनिवार्य शैली का उपयोग करने वाले तत्व नहीं बनाते हैं, इसके बजाय, हम JSX का उपयोग करते हुए एक घोषणात्मक शैली में लिखते हैं:

class MyComponent extends React.Component { render() { return <div>hello</div>; } } 

JSX मार्कअप वाला यह कोड कंपाइलर द्वारा निम्नलिखित में अनुवादित किया गया है:

 class MyComponent extends React.Component { render() { return React.createElement('div', null, 'hello'); } } 

यही है, संक्षेप में, यह React.createElement () के लिए एक स्पष्ट कॉल के माध्यम से एक तत्व बनाने के लिए एक अनिवार्य निर्माण में बदल जाता है। लेकिन यह निर्माण रेंडर () पद्धति के अंदर है, जिसे हम स्पष्ट रूप से कॉल नहीं करते हैं, रिएक्ट इस विधि को आवश्यक होने पर स्वयं कॉल करेगा। इसलिए, प्रतिक्रिया व्यक्त करने के लिए केवल घोषणा के रूप में है: हम वर्णन करते हैं कि हम क्या प्राप्त करना चाहते हैं, और प्रतिक्रिया यह निर्धारित करती है कि यह कैसे करना है।

अपनी छोटी प्रतिक्रिया लिखें


आवश्यक तकनीकी आधार प्राप्त करने के बाद, हम अपना स्वयं का रिएक्ट कार्यान्वयन शुरू करेंगे। यह एक बहुत ही सरलीकृत संस्करण होगा, आइए इसे फीक्ट कहते हैं।

मान लीजिए कि हम एक साधारण Feact एप्लीकेशन बनाना चाहते हैं जिसका कोड इस तरह दिखेगा:

 Feact.render(<h1>hello world</h1>, document.getElementById('root')); 

सबसे पहले, JSX के बारे में बताते हैं। यह ठीक एक "पीछे हटना" है, क्योंकि JSX पार्सिंग एक अलग बड़ा विषय है जिसे हम Feact के हमारे कार्यान्वयन के भाग के रूप में छोड़ देंगे। यदि हम संसाधित JSX के साथ काम कर रहे हैं, तो हम निम्नलिखित कोड देखेंगे:

 Feact.render( Feact.createElement('h1', null, 'hello world'), document.getElementById('root') ); 

यही है, हम JSX के बजाय Feact.createElement का उपयोग करते हैं। तो हम इस विधि को लागू करते हैं:

 const Feact = { createElement(type, props, children) { const element = { type, props: props || {} }; if (children) { element.props.children = children; } return element; } }; 

लौटाया गया तत्व एक साधारण वस्तु है जो यह दर्शाता है कि हम क्या प्रस्तुत करना चाहते हैं।

Feact.render () क्या करता है?


Feact.render () को कॉल करके, हम दो पैरामीटर पास करते हैं: हम जो प्रस्तुत करना चाहते हैं और जहां। यह किसी भी रिएक्ट एप्लिकेशन का शुरुआती बिंदु है। आइए Feact के रेंडर () विधि के कार्यान्वयन को लिखें:

 const Feact = { createElement() { /*   */ }, render(element, container) { const componentInstance = new FeactDOMComponent(element); return componentInstance.mountComponent(container); } }; 

रेंडर () पूरा होने पर, हमें एक समाप्त वेब पेज मिलता है। DOM तत्व FeactDOMComponent द्वारा बनाए गए हैं। आइए इसका कार्यान्वयन लिखें:

 class FeactDOMComponent { constructor(element) { this._currentElement = element; } mountComponent(container) { const domElement = document.createElement(this._currentElement.type); const text = this._currentElement.props.children; const textNode = document.createTextNode(text); domElement.appendChild(textNode); container.appendChild(domElement); this._hostNode = domElement; return domElement; } } 

MountComponent विधि एक DOM तत्व बनाता है और इसे इस में संग्रहीत करता है ।होस्टेनोड। हम अब इसका उपयोग नहीं करेंगे, लेकिन हम निम्नलिखित भागों में इस पर लौट आएंगे।

आवेदन के वर्तमान संस्करण को फिडल में देखा जा सकता है।

प्रतिक्रियात्मक रूप से एक आदिम कार्यान्वयन करने के लिए कोड की 40 पंक्तियाँ पर्याप्त थीं। हमने जो फीक्ट बनाया है, वह दुनिया को जीतने की संभावना नहीं है, लेकिन यह अच्छी तरह से प्रतिबिंबित करता है कि रिएक्ट के हुड के तहत क्या हो रहा है।

कस्टम घटक जोड़ना


हमारा फ़ीचर HTML (div, span, आदि) में न केवल तत्वों को प्रस्तुत करने में सक्षम होना चाहिए, बल्कि उपयोगकर्ता द्वारा मिश्रित कंपोनेंट भी:
पहले वर्णित Feact.createElement () विधि वर्तमान में ठीक है, इसलिए मैंने इसे कोड सूची में नहीं दोहराया।
 const Feact = { createClass(spec) { function Constructor(props) { this.props = props; } Constructor.prototype.render = spec.render; return Constructor; }, render(element, container) { //      //   , //    } }; const MyTitle = Feact.createClass({ render() { return Feact.createElement('h1', null, this.props.message); } }; Feact.render({ Feact.createElement(MyTitle, { message: 'hey there Feact' }), document.getElementById('root') ); 

मुझे याद दिलाएं, यदि JSX उपलब्ध था, तो रेंडर () पद्धति को कॉल करना इस तरह दिखेगा:

 Feact.render( <MyTitle message="hey there Feact" />, document.getElementById('root') ); 

हम बनाने के लिए कस्टम घटक वर्ग पारित कर दिया। एक आभासी प्रतिक्रिया तत्व या तो एक नियमित DOM तत्व या एक कस्टम घटक का प्रतिनिधित्व कर सकता है। हम उन्हें निम्नानुसार भेद करेंगे: यदि हम एक स्ट्रिंग प्रकार पास करते हैं, तो यह एक DOM तत्व है; यदि कोई फ़ंक्शन है, तो यह तत्व एक कस्टम घटक का प्रतिनिधित्व करता है।

Feact.render () में सुधार


यदि आप इस समय कोड को करीब से देखते हैं, तो आप देखेंगे कि Feact.render () कस्टम घटकों को संसाधित नहीं कर सकता है। चलो इसे ठीक करें:

 Feact = { render(element, container) { const componentInstance = new FeactCompositeComponentWrapper(element); return componentInstance.mountComponent(container); } } class FeactCompositeComponentWrapper { constructor(element) { this._currentElement = element; } mountComponent(container) { const Component = this._currentElement.type; const componentInstance = new Component(this._currentElement.props); const element = componentInstance.render(); const domComponentInstance = new FeactDOMComponent(element); return domComponentInstance.mountComponent(container); } } 

हमने पारित आइटम के लिए एक आवरण बनाया है। आवरण के अंदर, हम उपयोगकर्ता घटक वर्ग का एक उदाहरण बनाते हैं और इसके घटक को कहते हैं ।स्ट्रेंडर () विधि। इस विधि के परिणाम को FeactDOMComponent पर पारित किया जा सकता है, जहां संबंधित DOM तत्व बनाए जाएंगे।

अब हम कस्टम घटकों को बना और सौंप सकते हैं। Feact कस्टम घटकों के आधार पर DOM नोड्स का निर्माण करेगा, और हमारे कस्टम घटकों के गुणों (प्रॉप्स) के आधार पर उन्हें बदल देगा। यह हमारे फीक्ट में एक महत्वपूर्ण सुधार है।
ध्यान दें कि FeactCompositeComponentWrapper सीधे FeactDOMComponent बनाता है। ऐसा घनिष्ठ संबंध खराब है। हम इसे बाद में ठीक कर देंगे। यदि React का समान करीबी कनेक्शन होता, तो केवल वेब एप्लिकेशन ही बनाए जा सकते थे। ReactCompositeComponentWrapper की एक अतिरिक्त परत जोड़ने से आप वर्चुअल तत्वों के प्रबंधन और देशी तत्वों के अंतिम प्रदर्शन के लिए रिएक्ट लॉजिक को अलग कर सकते हैं, जो आपको वेब एप्लिकेशन बनाते समय न केवल रिएक्ट का उपयोग करने की अनुमति देता है, बल्कि उदाहरण के लिए, मोबाइल के लिए रिएक्ट नेटिव।

कस्टम घटक वृद्धि


निर्मित कस्टम घटक केवल मूल डोम तत्वों को वापस कर सकते हैं, यदि हम अन्य कस्टम घटकों को वापस करने का प्रयास करते हैं, तो हमें एक त्रुटि मिलती है। इस दोष को ठीक करो। कल्पना करें कि हम त्रुटियों के बिना निम्नलिखित कोड निष्पादित करना चाहेंगे:

 const MyMessage = Feact.createClass({ render() { if (this.props.asTitle) { return Feact.createElement(MyTitle, { message: this.props.message }); } else { return Feact.createElement('p', null, this.props.message); } } } 

एक कस्टम घटक का रेंडर () विधि देशी डोम तत्व या किसी अन्य कस्टम घटक को वापस कर सकती है। यदि asTitle गुण सत्य है, तो FeactCompositeComponentWrapper FeactDOMComponent के लिए कस्टम घटक लौटाएगा जहां त्रुटि होगी। FeactCompositeComponentWrapper को ठीक करें:

 class FeactCompositeComponentWrapper { constructor(element) { this._currentElement = element; } mountComponent(container) { const Component = this._currentElement.type; const componentInstance = new Component(this._currentElement.props); let element = componentInstance.render(); while (typeof element.type === 'function') { element = (new element.type(element.props)).render(); } const domComponentInstance = new FeactDOMComponent(element); domComponentInstance.mountComponent(container); } } 

सच में, हमने अब मौजूदा जरूरतों को पूरा करने के लिए एक बैसाखी बनाई है। रेंडर मेथड के लिए एक कॉल चाइल्ड कंपोनेंट्स को तब तक लौटाएगी जब तक कि यह एक देशी DOM एलिमेंट नहीं लौटाता। यह बुरा है क्योंकि इस तरह के बाल घटक जीवन चक्र में भाग नहीं लेंगे। उदाहरण के लिए, इस मामले में, हम कंपोनेंटमाउंट कॉल को लागू नहीं कर पाएंगे। हम इसे बाद में ठीक कर देंगे।

और फिर से हम Feact.render () को ठीक करते हैं


Feact.render () का पहला संस्करण केवल मूल डोम तत्वों को संसाधित कर सकता है। अब केवल उपयोगकर्ता-परिभाषित घटकों को मूल समर्थन के बिना सही ढंग से संसाधित किया जाता है। दोनों मामलों को संभालना आवश्यक है। आप एक कारखाना लिख ​​सकते हैं जो पारित किए गए तत्व के प्रकार के आधार पर एक घटक बनाएगा, लेकिन रिएक्ट ने एक अलग तरीका चुना: किसी भी आने वाले घटक को किसी अन्य घटक में लपेटें:

 const TopLevelWrapper = function(props) { this.props = props; }; TopLevelWrapper.prototype.render = function() { return this.props; }; const Feact = { render(element, container) { const wrapperElement = this.createElement(TopLevelWrapper, element); const componentInstance = new FeactCompositeComponentWrapper(wrapperElement); //   } }; 

TopLevelWrapper अनिवार्य रूप से एक कस्टम घटक है। इसे Feact.createClass () कहकर भी परिभाषित किया जा सकता है। इसका रेंडर तरीका बस इसमें दिए गए तत्व को वापस करता है। अब प्रत्येक तत्व TopLevelWrapper में लिपटा हुआ है, और FeactCompositeComponentWrapper को इनपुट के रूप में हमेशा एक कस्टम घटक प्राप्त होगा।

पहले भाग का निष्कर्ष


हमने फीक्ट लागू किया है, जो घटकों को प्रस्तुत कर सकता है। उत्पन्न कोड प्रतिपादन की मूल अवधारणाओं को दर्शाता है। रिएक्ट में वास्तविक प्रतिपादन अधिक जटिल है, और यह घटनाओं, फोकस, विंडो स्क्रॉलिंग, प्रदर्शन, आदि को कवर करता है।

पहले भाग की अंतिम jsfiddle

Source: https://habr.com/ru/post/hi458916/


All Articles