मराठी

React च्या कंपोनंट आर्किटेक्चरमध्ये सखोल अभ्यास, कंपोझिशन आणि इनहेरिटन्सची तुलना. React कंपोझिशनला का प्राधान्य देते ते शिका आणि स्केलेबल, रियुजेबल कंपोनंट्स तयार करण्यासाठी HOCs, रेंडर प्रॉप्स आणि हुक्ससारखे पॅटर्न एक्सप्लोर करा.

React कंपोनंट आर्किटेक्चर: कंपोझिशन इनहेरिटन्सवर मात का करते

सॉफ्टवेअर डेव्हलपमेंटच्या जगात, आर्किटेक्चर सर्वोपरी आहे. आपण आपल्या कोडला ज्या प्रकारे संरचित करतो ते त्याची स्केलेबिलिटी, देखरेखक्षमता आणि रियुजेबिलिटी निश्चित करते. React सह काम करणाऱ्या डेव्हलपर्ससाठी, सर्वात मूलभूत आर्किटेक्चरल निर्णयांपैकी एक म्हणजे कंपोनंट्समध्ये लॉजिक आणि UI कसे शेअर करायचे याबद्दल आहे. हे आपल्याला ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंगमधील एका क्लासिक वादविवादाकडे नेते, React च्या कंपोनंट-आधारित जगात त्याची पुनर्कल्पना केली गेली आहे: कंपोझिशन विरुद्ध इनहेरिटन्स.

जर तुम्ही Java किंवा C++ सारख्या क्लासिकल ऑब्जेक्ट-ओरिएंटेड भाषांमधील पार्श्वभूमीतून आले असाल, तर इनहेरिटन्स हा पहिला नैसर्गिक पर्याय असू शकतो. 'इज-ए' संबंध तयार करण्यासाठी ही एक शक्तिशाली संकल्पना आहे. तथापि, अधिकृत React डॉक्युमेंटेशन एक स्पष्ट आणि मजबूत शिफारस देते: "Facebook मध्ये, आम्ही हजारो कंपोनंट्समध्ये React वापरतो आणि आम्हाला असे कोणतेही यूज केसेस आढळले नाहीत जिथे आम्ही कंपोनंट इनहेरिटन्स हायरार्की तयार करण्याची शिफारस करू."

ही पोस्ट या आर्किटेक्चरल निवडीचे सर्वसमावेशक एक्सप्लोरेशन प्रदान करेल. React संदर्भात इनहेरिटन्स आणि कंपोझिशनचा अर्थ काय आहे हे आम्ही उघड करू, कंपोझिशन हा मुहावरेदार आणि उत्कृष्ट दृष्टिकोन का आहे हे दर्शवू आणि शक्तिशाली पॅटर्न—हायर-ऑर्डर कंपोनंट्सपासून ते आधुनिक हुक्सपर्यंत—जे कंपोझिशनला जागतिक प्रेक्षकांसाठी मजबूत आणि लवचिक ॲप्लिकेशन्स तयार करण्यासाठी डेव्हलपरचा सर्वोत्तम मित्र बनवतात.

जुन्या रक्षकांना समजून घेणे: इनहेरिटन्स काय आहे?

इनहेरिटन्स हा ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग (OOP) चा एक महत्त्वाचा आधारस्तंभ आहे. हे एका नवीन क्लासला (सबक्लास किंवा चाइल्ड) विद्यमान क्लासचे (सुपरक्लास किंवा पॅरेंट) गुणधर्म आणि पद्धती प्राप्त करण्यास अनुमती देते. हे घट्टपणे जोडलेले 'इज-ए' नाते तयार करते. उदाहरणार्थ, GoldenRetriever इज ए Dog, जे इज एन Animal आहे.

नॉन-React संदर्भात इनहेरिटन्स

संकल्पना दृढ करण्यासाठी एक साधे JavaScript क्लास उदाहरण पाहू:

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // Calls the parent constructor
    this.breed = breed;
  }

  speak() { // Overrides the parent method
    console.log(`${this.name} barks.`);
  }

  fetch() {
    console.log(`${this.name} is fetching the ball!`);
  }
}

const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); // Output: "Buddy barks."
myDog.fetch(); // Output: "Buddy is fetching the ball!"

या मॉडेलमध्ये, Dog क्लासला आपोआप name प्रॉपर्टी आणि speak मेथड Animal कडून मिळते. हे स्वतःच्या मेथड्स (fetch) देखील ॲड करू शकते आणि विद्यमान मेथड्स ओव्हरराइड करू शकते. हे एक कठोर हायरार्की तयार करते.

React मध्ये इनहेरिटन्स का अयशस्वी ठरते

हे 'इज-ए' मॉडेल काही डेटा स्ट्रक्चर्ससाठी काम करत असले तरी, React मधील UI कंपोनंट्सना लागू केल्यावर ते महत्त्वपूर्ण समस्या निर्माण करते:

या समस्यांमुळे, React टीमने लायब्ररी एका अधिक लवचिक आणि शक्तिशाली पॅराडाइमभोवती डिझाइन केली: कंपोझिशन.

React चा मार्ग स्वीकारणे: कंपोझिशनची शक्ती

कंपोझिशन हे एक डिझाइन तत्त्व आहे जे 'हॅज-ए' किंवा 'यूज-ए' संबंधाला अनुकूल करते. कंपोनंट दुसरा कंपोनंट असण्याऐवजी, त्यात इतर कंपोनंट्स आहेत किंवा त्यांची फंक्शनॅलिटी वापरतात. कंपोनंट्सना बिल्डिंग ब्लॉक्स—लेगो ब्रिक्ससारखे—मानले जातात, जे कठोर हायरार्कीमध्ये लॉक न होता जटिल UIs तयार करण्यासाठी विविध प्रकारे एकत्र केले जाऊ शकतात.

React चे कंपोझिशनल मॉडेल अविश्वसनीयपणे बहुमुखी आहे आणि ते अनेक मुख्य पॅटर्नमध्ये प्रकट होते. चला त्यांचा शोध घेऊ, सर्वात मूलभूत ते सर्वात आधुनिक आणि शक्तिशाली पर्यंत.

टेक्निक 1: props.children सह कंटेनमेंट

कंपोझिशनचे सर्वात सरळ स्वरूप म्हणजे कंटेनमेंट. येथे कंपोनंट एक सामान्य कंटेनर किंवा 'बॉक्स' म्हणून कार्य करतो आणि त्याची सामग्री पॅरेंट कंपोनंटकडून पास केली जाते. React मध्ये यासाठी एक विशेष, अंगभूत प्रॉप आहे: props.children.

कल्पना करा की तुम्हाला Card कंपोनंटची आवश्यकता आहे जो सातत्यपूर्ण बॉर्डर आणि शॅडोसह कोणतीही सामग्री रॅप करू शकेल. इनहेरिटन्सद्वारे TextCard, ImageCard आणि ProfileCard व्ह্যারिएंट्स तयार करण्याऐवजी, तुम्ही एक सामान्य Card कंपोनंट तयार करा.

// Card.js - एक सामान्य कंटेनर कंपोनंट
function Card(props) {
  return (
    <div className="card">
      {props.children}
    </div>
  );
}

// App.js - Card कंपोनंट वापरणे
function App() {
  return (
    <div>
      <Card>
        <h1>वेलकम!</h1>
        <p>ही सामग्री Card कंपोनंटच्या आत आहे.</p>
      </Card>

      <Card>
        <img src="/path/to/image.jpg" alt="एक उदाहरण इमेज" />
        <p>ही एक इमेज कार्ड आहे.</p>
      </Card>
    </div>
  );
}

येथे, Card कंपोनंटला त्यात काय आहे हे माहित नसते किंवा त्याची पर्वा नसते. हे फक्त रॅपर स्टाइलिंग प्रदान करते. ओपनिंग आणि क्लोजिंग <Card> टॅग्ज दरम्यानची सामग्री आपोआप props.children म्हणून पास होते. हे डीकपलिंग आणि रियुजेबिलिटीचे सुंदर उदाहरण आहे.

टेक्निक 2: प्रॉप्ससह स्पेशलायझेशन

कधीकधी, कंपोनंटला इतर कंपोनंट्सद्वारे भरण्यासाठी एकापेक्षा जास्त 'होल्स' आवश्यक असतात. तुम्ही props.children वापरू शकता, परंतु अधिक स्पष्ट आणि संरचित मार्ग म्हणजे कंपोनंट्सला नियमित प्रॉप्स म्हणून पास करणे. या पॅटर्नला बर्‍याचदा स्पेशलायझेशन म्हणतात.

Modal कंपोनंटचा विचार करा. मॉडेलमध्ये सामान्यत: शीर्षक विभाग, सामग्री विभाग आणि क्रिया विभाग (जसे की "कन्फर्म" किंवा "कॅन्सल" बटणे) असतात. आम्ही आमचे Modal हे विभाग प्रॉप्स म्हणून स्वीकारण्यासाठी डिझाइन करू शकतो.

// Modal.js - अधिक स्पेशलाइज्ड कंटेनर
function Modal(props) {
  return (
    <div className="modal-backdrop">
      <div className="modal-content">
        <div className="modal-header">{props.title}</div>
        <div className="modal-body">{props.body}</div>
        <div className="modal-footer">{props.actions}</div>
      </div>
    </div>
  );
}

// App.js - विशिष्ट कंपोनंट्ससह Modal वापरणे
function App() {
  const confirmationTitle = <h2>ॲक्शन कन्फर्म करा</h2>;
  const confirmationBody = <p>तुम्ही या ॲक्शनसोबत पुढे जाण्यासाठी निश्चित आहात का?</p>;
  const confirmationActions = (
    <div>
      <button>कन्फर्म</button>
      <button>कॅन्सल</button>
    </div>
  );

  return (
    <Modal
      title={confirmationTitle}
      body={confirmationBody}
      actions={confirmationActions}
    />
  );
}

या उदाहरणात, Modal हा अत्यंत रियुजेबल लेआउट कंपोनंट आहे. आम्ही त्याचे title, body आणि actions साठी विशिष्ट JSX एलिमेंट्स पास करून ते स्पेशलाइज करतो. ConfirmationModal आणि WarningModal सबक्लासेस तयार करण्यापेक्षा हे अधिक लवचिक आहे. आम्ही गरजेनुसार वेगवेगळ्या सामग्रीसह Modal कंपोझ करतो.

टेक्निक 3: हायर-ऑर्डर कंपोनंट्स (HOCs)

नॉन-UI लॉजिक शेअर करण्यासाठी, जसे की डेटा फेचिंग, ऑथेंटिकेशन किंवा लॉगिंग, React डेव्हलपर्स ऐतिहासिकदृष्ट्या हायर-ऑर्डर कंपोनंट्स (HOCs) नावाच्या पॅटर्नकडे वळले. आधुनिक React मध्ये हुक्सने मोठ्या प्रमाणात बदलले असले तरी, ते React च्या कंपोझिशन स्टोरीमधील एक महत्त्वाचा उत्क्रांतीचा टप्पा दर्शवतात आणि अजूनही बर्‍याच कोडबेसमध्ये अस्तित्वात आहेत हे समजून घेणे महत्त्वाचे आहे.

HOC हे एक फंक्शन आहे जे कंपोनंटला आर्ग्युमेंट म्हणून घेते आणि एक नवीन, वर्धित कंपोनंट रिटर्न करते.

चला withLogger नावाचे HOC तयार करू जे जेव्हा कंपोनंट अपडेट होतो तेव्हा त्याचे प्रॉप्स लॉग करते. हे डीबगिंगसाठी उपयुक्त आहे.

// withLogger.js - HOC
import React, { useEffect } from 'react';

function withLogger(WrappedComponent) {
  // हे एक नवीन कंपोनंट रिटर्न करते...
  return function EnhancedComponent(props) {
    useEffect(() => {
      console.log('नवीन प्रॉप्ससह कंपोनंट अपडेट केला:', props);
    }, [props]);

    // ... जे मूळ प्रॉप्ससह मूळ कंपोनंट रेंडर करते.
    return <WrappedComponent {...props} />;
  };
}

// MyComponent.js - वर्धित करण्यासाठी कंपोनंट
function MyComponent({ name, age }) {
  return (
    <div>
      <h1>नमस्कार, {name}!</h1>
      <p>तुमचे वय {age} वर्षे आहे.</p>
    </div>
  );
}

// वर्धित कंपोनंट एक्सपोर्ट करणे
export default withLogger(MyComponent);

withLogger फंक्शन MyComponent रॅप करते, ज्यामुळे MyComponent चा अंतर्गत कोड बदलल्याशिवाय त्याला नवीन लॉगिंग क्षमता मिळतात. आम्ही हेच HOC इतर कोणत्याही कंपोनंटला समान लॉगिंग फीचर देण्यासाठी लागू करू शकतो.

HOCs सह आव्हाने:

टेक्निक 4: रेंडर प्रॉप्स

रेंडर प्रॉप पॅटर्न HOCs च्या काही त्रुटींवर उपाय म्हणून उदयास आला. हे लॉजिक शेअर करण्याचा अधिक स्पष्ट मार्ग देते.

रेंडर प्रॉप असलेला कंपोनंट प्रॉप म्हणून फंक्शन घेतो (सामान्यतः render असे नाव दिलेले असते) आणि काय रेंडर करायचे हे निर्धारित करण्यासाठी त्या फंक्शनला कॉल करतो, कोणतीही स्टेट किंवा लॉजिक आर्ग्युमेंट्स म्हणून पास करतो.

चला MouseTracker कंपोनंट तयार करू जे माउसचे X आणि Y कोऑर्डिनेट्स ट्रॅक करते आणि ते वापरू इच्छिणाऱ्या कोणत्याही कंपोनंटला उपलब्ध करून देते.

// MouseTracker.js - रेंडर प्रॉपसह कंपोनंट
import React, { useState, useEffect } from 'react';

function MouseTracker({ render }) {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseMove = (event) => {
    setPosition({ x: event.clientX, y: event.clientY });
  };

  useEffect(() => {
    window.addEventListener('mousemove', handleMouseMove);
    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
    };
  }, []);

  // स्टेटसह रेंडर फंक्शन कॉल करा
  return render(position);
}

// App.js - MouseTracker वापरणे
function App() {
  return (
    <div>
      <h1>तुमचा माउस फिरवा!</h1>
      <MouseTracker
        render={mousePosition => (
          <p>सध्याचे माउसचे स्थान ({mousePosition.x}, {mousePosition.y}) आहे</p>
        )}
      />
    </div>
  );
}

येथे, MouseTracker माउस मूव्हमेंट ट्रॅक करण्यासाठी सर्व लॉजिक एन्कॅप्स्युलेट करते. ते स्वतःहून काहीही रेंडर करत नाही. त्याऐवजी, ते रेंडरिंग लॉजिक त्याच्या render प्रॉपला सोपवते. हे HOCs पेक्षा अधिक स्पष्ट आहे कारण तुम्हाला JSX मध्ये mousePosition डेटा नेमका कुठून येत आहे हे दिसते.

children प्रॉपचा वापर फंक्शन म्हणून देखील केला जाऊ शकतो, जो या पॅटर्नचा एक सामान्य आणि सुंदर प्रकार आहे:

// फंक्शन म्हणून चिल्ड्रन वापरणे
<MouseTracker>
  {mousePosition => (
    <p>सध्याचे माउसचे स्थान ({mousePosition.x}, {mousePosition.y}) आहे</p>
  )}
</MouseTracker>

टेक्निक 5: हुक्स (आधुनिक आणि पसंतीचा दृष्टिकोन)

React 16.8 मध्ये सादर केलेले, हुक्सने आपण React कंपोनंट्स कसे लिहितो यात क्रांती घडवली. ते तुम्हाला फंक्शनल कंपोनंट्समध्ये स्टेट आणि इतर React फीचर्स वापरण्याची परवानगी देतात. सर्वात महत्त्वाचे म्हणजे, कस्टम हुक्स कंपोनंट्समध्ये स्टेटफुल लॉजिक शेअर करण्यासाठी सर्वात सुंदर आणि थेट उपाय प्रदान करतात.

हुक्स HOCs आणि रेंडर प्रॉप्सच्या समस्या अधिक स्वच्छ मार्गाने सोडवतात. चला आपले MouseTracker उदाहरण useMousePosition नावाच्या कस्टम हुक मध्ये रिफॅक्टर करू.

// hooks/useMousePosition.js - एक कस्टम हुक
import { useState, useEffect } from 'react';

export function useMousePosition() {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const handleMouseMove = (event) => {
      setPosition({ x: event.clientX, y: event.clientY });
    };

    window.addEventListener('mousemove', handleMouseMove);
    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
    };
  }, []); // रिक्त डिपेंडेंसी ॲरे म्हणजे हा इफेक्ट फक्त एकदाच रन होतो

  return position;
}

// DisplayMousePosition.js - हुक वापरणारा कंपोनंट
import { useMousePosition } from './hooks/useMousePosition';

function DisplayMousePosition() {
  const position = useMousePosition(); // फक्त हुक कॉल करा!

  return (
    <p>
      माउसचे स्थान ({position.x}, {position.y}) आहे
    </p>
  );
}

// दुसरा कंपोनंट, कदाचित एक इंटरॲक्टिव्ह एलिमेंट
import { useMousePosition } from './hooks/useMousePosition';

function InteractiveBox() {
  const { x, y } = useMousePosition();

  const style = {
    position: 'absolute',
    top: y - 25, // कर्सरवर बॉक्स सेंटर करा
    left: x - 25,
    width: '50px',
    height: '50px',
    backgroundColor: 'lightblue',
  };

  return <div style={style} />;
}

हा एक मोठा सुधारणा आहे. येथे 'रॅपर हेल' नाही, प्रॉप नेमिंग कॉलिजन नाही आणि कोणतेही जटिल रेंडर प्रॉप फंक्शन नाहीत. लॉजिक पूर्णपणे रियुजेबल फंक्शनमध्ये (`useMousePosition`) डीकपल्ड आहे आणि कोणताही कंपोनंट एका सिंगल, स्पष्ट कोड लाईनसह त्या स्टेटफुल लॉजिकमध्ये 'हुक इन' करू शकतो. कस्टम हुक्स हे आधुनिक React मधील कंपोझिशनचे अंतिम स्वरूप आहेत, जे तुम्हाला रियुजेबल लॉजिक ब्लॉक्सची स्वतःची लायब्ररी तयार करण्यास अनुमती देतात.

एक त्वरित तुलना: React मध्ये कंपोझिशन विरुद्ध इनहेरिटन्स

React संदर्भात मुख्य फरकांचा सारांश देण्यासाठी, येथे थेट तुलना आहे:

पैलू इनहेरिटन्स (React मध्ये अँटी-पॅटर्न) कंपोझिशन (React मध्ये पसंतीचे)
संबंध 'इज-ए' संबंध. एक स्पेशलाइज्ड कंपोनंट बेस कंपोनंटचे आहे व्हर्जन आहे. 'हॅज-ए' किंवा 'यूज-ए' संबंध. एक जटिल कंपोनंट लहान कंपोनंट ठेवतो किंवा सामायिक लॉजिक वापरतो.
कपलिंग उच्च. चाइल्ड कंपोनंट्स त्यांच्या पॅरेंटच्या इम्प्लिमेंटेशनशी घट्टपणे जोडलेले आहेत. कमी. कंपोनंट्स स्वतंत्र आहेत आणि सुधारणा न करता वेगवेगळ्या संदर्भांमध्ये रियूज केले जाऊ शकतात.
लवचिकता कमी. कठोर, क्लास-आधारित हायरार्कीमुळे वेगवेगळ्या कंपोनंट ट्रीमध्ये लॉजिक शेअर करणे कठीण होते. उच्च. लॉजिक आणि UI असंख्य मार्गांनी एकत्र केले जाऊ शकतात आणि रियूज केले जाऊ शकतात, जसे की बिल्डिंग ब्लॉक्स.
कोड रियुजेबिलिटी पूर्वपरिभाषित हायरार्कीपर्यंत मर्यादित. जेव्हा तुम्हाला फक्त "केळे" हवे असते तेव्हा तुम्हाला संपूर्ण "गोरिल्ला" मिळतो. उत्कृष्ट. लहान, केंद्रित कंपोनंट्स आणि हुक्स संपूर्ण ॲप्लिकेशनमध्ये वापरले जाऊ शकतात.
React मुहावरा अधिकृत React टीमने निरुत्साहित केले. React ॲप्लिकेशन्स तयार करण्यासाठी शिफारस केलेला आणि मुहावरेदार दृष्टिकोन.

निष्कर्ष: कंपोझिशनमध्ये विचार करा

कंपोझिशन आणि इनहेरिटन्सचा वाद हा सॉफ्टवेअर डिझाइनमधील मूलभूत विषय आहे. इनहेरिटन्सला क्लासिकल OOP मध्ये स्थान असले तरी, UI डेव्हलपमेंटचे डायनॅमिक, कंपोनंट-आधारित स्वरूप React साठी ते योग्य नाही. लायब्ररी मूलभूतपणे कंपोझिशन स्वीकारण्यासाठी डिझाइन केलेली आहे.

कंपोझिशनला प्राधान्य देऊन, तुम्हाला हे मिळते:

एक जागतिक React डेव्हलपर म्हणून, कंपोझिशनमध्ये प्रभुत्व मिळवणे हे केवळ सर्वोत्तम पद्धतींचे अनुसरण करण्याबद्दल नाही—तर React ला एक शक्तिशाली आणि उत्पादक साधन बनवणारे मूळ तत्त्वज्ञान समजून घेण्याबद्दल आहे. लहान, केंद्रित कंपोनंट्स तयार करून सुरुवात करा. सामान्य कंटेनर्ससाठी props.children आणि स्पेशलायझेशनसाठी प्रॉप्स वापरा. लॉजिक शेअर करण्यासाठी, प्रथम कस्टम हुक्ससाठी पोहोचा. कंपोझिशनमध्ये विचार करून, तुम्ही सुंदर, मजबूत आणि स्केलेबल React ॲप्लिकेशन्स तयार करण्याच्या मार्गावर असाल जे वेळेच्या कसोटीवर टिकून राहतील.