റിയാക്റ്റിൻ്റെ കോമ്പണന്റ് ആർക്കിടെക്ചറിനെക്കുറിച്ചുള്ള ആഴത്തിലുള്ള പഠനം, കോമ്പോസിഷനും ഇൻഹെറിറ്റൻസും താരതമ്യം ചെയ്യുന്നു.
റിയാക്റ്റ് കോമ്പണന്റ് ആർക്കിടെക്ചർ: ഇൻഹെറിറ്റൻസിനെക്കാൾ കോമ്പോസിഷൻ്റെ വിജയം
സോഫ്റ്റ്വെയർ ഡെവലപ്മെൻ്റ് ലോകത്ത്, ആർക്കിടെക്ചർ പരമപ്രധാനമാണ്. നമ്മുടെ കോഡ് ഘടന ചെയ്യുന്നത് അതിൻ്റെ സ്കേലബിലിറ്റി, പരിപാലനം, പുനരുപയോഗം എന്നിവ നിർണ്ണയിക്കുന്നു. റിയാക്റ്റിൽ പ്രവർത്തിക്കുന്ന ഡെവലപ്പർമാർക്ക്, കോമ്പണന്റുകൾക്കിടയിൽ ലോജിക്കും UI-യും പങ്കിടുന്നത് എങ്ങനെ എന്നതിനെ കേന്ദ്രീകരിച്ച് ഏറ്റവും അടിസ്ഥാനപരമായ ആർക്കിടെക്ചറൽ തീരുമാനങ്ങളുണ്ട്. ഇത് ക്ലാസിക്കൽ ഒബ്ജക്റ്റ്-ഓറിയൻ്റഡ് പ്രോഗ്രാമിംഗിലെ ഒരു ക്ലാസിക് ചർച്ചയിലേക്ക് നമ്മെ കൊണ്ടുവരുന്നു, റിയാക്റ്റിൻ്റെ കോമ്പണന്റ് അധിഷ്ഠിത ലോകത്തിനായി പുനർരൂപകൽപ്പന ചെയ്തത്: കോമ്പോസിഷൻ വേഴ്സസ് ഇൻഹെറിറ്റൻസ്.
Java അല്ലെങ്കിൽ C++ പോലുള്ള ക്ലാസിക്കൽ ഒബ്ജക്റ്റ്-ഓറിയൻ്റഡ് ഭാഷകളിൽ നിന്നുള്ള പശ്ചാത്തലത്തിൽ നിന്ന് നിങ്ങൾക്ക് വരികയാണെങ്കിൽ, ഇൻഹെറിറ്റൻസ് ഒരു സ്വാഭാവിക ആദ്യ തിരഞ്ഞെടുപ്പായി തോന്നാം. 'is-a' ബന്ധങ്ങൾ സൃഷ്ടിക്കുന്നതിനുള്ള ശക്തമായ ഒരു ആശയമാണിത്. എന്നിരുന്നാലും, ഔദ്യോഗിക റിയാക്റ്റ് ഡോക്യുമെൻ്റേഷൻ വ്യക്തവും ശക്തവുമായ ശുപാർശ നൽകുന്നു: "Facebook-ൽ, ഞങ്ങൾ റിയാക്റ്റ് ആയിരക്കണക്കിന് കോമ്പണന്റുകളിൽ ഉപയോഗിക്കുന്നു, കോമ്പണന്റ് ഇൻഹെറിറ്റൻസ് ശ്രേണികൾ സൃഷ്ടിക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്ന ഏതെങ്കിലും ഉപയോഗ കേസുകൾ ഞങ്ങൾ കണ്ടെത്തിയിട്ടില്ല."
ഈ പോസ്റ്റ് ഈ ആർക്കിടെക്ചറൽ ചോയിസിൻ്റെ സമഗ്രമായ ഒരു വിശകലനം നൽകും. റിയാക്റ്റ് സന്ദർഭത്തിൽ ഇൻഹെറിറ്റൻസും കോമ്പോസിഷനും എന്താണെന്ന് ഞങ്ങൾ അനാവരണം ചെയ്യും, എന്തുകൊണ്ടാണ് കോമ്പോസിഷൻ റിയാക്റ്റ് രീതിയും ശ്രേഷ്ഠവുമായ സമീപനമാണെന്ന് ഞങ്ങൾ പ്രകടമാക്കും, കൂടാതെ ഹയർ-ഓർഡർ കോമ്പണന്റുകളിൽ നിന്ന് ആധുനിക ഹുക്ക്സ് വരെയുള്ള ശക്തമായ പാറ്റേണുകൾ ഞങ്ങൾ പരിശോധിക്കും - ഇത് കോമ്പോസിഷനെ ഒരു ഡെവലപ്പർ്മാരുടെ ഏറ്റവും നല്ല കൂട്ടാളിയാക്കി മാറ്റുന്നു. ലോകമെമ്പാടുമുള്ള പ്രേക്ഷകർക്കായി ശക്തമായതും അയവുള്ളതുമായ അപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ.
പഴയ രീതി മനസ്സിലാക്കുന്നു: എന്താണ് ഇൻഹെറിറ്റൻസ്?
ഇൻഹെറിറ്റൻസ് ഒബ്ജക്റ്റ്-ഓറിയൻ്റഡ് പ്രോഗ്രാമിംഗിൻ്റെ (OOP) ഒരു പ്രധാന തൂണാണ്. ഇത് ഒരു പുതിയ ക്ലാസിന് (സബ്ക്ലാസ് അല്ലെങ്കിൽ ചൈൽഡ്) നിലവിലുള്ള ഒരു ക്ലാസിൻ്റെ (സൂപ്പർക്ലാസ് അല്ലെങ്കിൽ പാരൻ്റ്) പ്രോപ്പർട്ടികളും രീതികളും നേടാൻ അനുവദിക്കുന്നു. ഇത് ഒരു കർശനമായി ബന്ധിതമായ 'is-a' ബന്ധം സൃഷ്ടിക്കുന്നു. ഉദാഹരണത്തിന്, ഒരു GoldenRetriever
Dog
ആണ്, അത് Animal
ആണ്.
റിയാക്റ്റ് ഇതര സന്ദർഭത്തിലെ ഇൻഹെറിറ്റൻസ്
ഈ ആശയം ഉറപ്പിക്കാൻ നമുക്ക് ഒരു ലളിതമായ ജാവാസ്ക്രിപ്റ്റ് ക്ലാസ് ഉദാഹരണം നോക്കാം:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // പാരൻ്റ് കൺസ്ട്രക്റ്റർ വിളിക്കുന്നു
this.breed = breed;
}
speak() { // പാരൻ്റ് മെത്തേഡ് ഓവർറൈഡ് ചെയ്യുന്നു
console.log(`${this.name} barks.`);
}
fetch() {
console.log(`${this.name} is fetching the ball!`);
}
}
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); // ഔട്ട്പുട്ട്: "Buddy barks."
myDog.fetch(); // ഔട്ട്പുട്ട്: "Buddy is fetching the ball!"
ഈ മോഡലിൽ, Dog
ക്ലാസ് Animal
ൽ നിന്ന് name
പ്രോപ്പർട്ടിയും speak
മെത്തേഡും സ്വയമേവ നേടുന്നു. ഇതിന് അതിൻ്റേതായ രീതികളും (fetch
) നിലവിലുള്ളവ ഓവർറൈഡ് ചെയ്യാനും കഴിയും. ഇത് ഒരു കർശനമായ ശ്രേണി സൃഷ്ടിക്കുന്നു.
റിയാക്റ്റിൽ ഇൻഹെറിറ്റൻസ് പരാജയപ്പെടുന്നത് എന്തുകൊണ്ട്
ഈ 'is-a' മോഡൽ ചില ഡാറ്റാ ഘടനകൾക്ക് പ്രവർത്തിക്കുമെങ്കിലും, റിയാക്റ്റിലെ UI കോമ്പണന്റുകളിൽ പ്രയോഗിക്കുമ്പോൾ ഇത് കാര്യമായ പ്രശ്നങ്ങൾ സൃഷ്ടിക്കുന്നു:
- കർശനമായ ബന്ധം (Tight Coupling): ഒരു കോമ്പണന്റ് ഒരു ബേസ് കോമ്പണന്റിൽ നിന്ന് ഇൻഹെറിറ്റ് ചെയ്യുമ്പോൾ, അത് അതിൻ്റെ പാരൻ്റിൻ്റെ പ്രവർത്തനങ്ങളുമായി കർശനമായി ബന്ധിതമാകുന്നു. ബേസ് കോമ്പണന്റിലെ ഒരു മാറ്റം ശൃംഖലയിലെ ഒന്നിലധികം ചൈൽഡ് കോമ്പണന്റുകളെ പ്രതീക്ഷിക്കാത്ത രീതിയിൽ തകർക്കാൻ സാധ്യതയുണ്ട്. ഇത് റീഫാക്ടറിംഗ്, പരിപാലനം എന്നിവ ദുർബലമാക്കുന്നു.
- അയവില്ലാത്ത ലോജിക് പങ്കിടൽ: ഒരേ 'is-a' ശ്രേണിയിൽ ഉൾക്കൊള്ളാത്ത കോമ്പണന്റുകളുമായി ഒരു പ്രത്യേക പ്രവർത്തനക്ഷമത, ഡാറ്റാ ഫെച്ചിംഗ് പോലുള്ളവ പങ്കിടാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുവെങ്കിൽ എന്തുചെയ്യും? ഉദാഹരണത്തിന്, ഒരു
UserProfile
-ഉം ഒരുProductList
-ഉം ഡാറ്റാ ഫെച്ച് ചെയ്യേണ്ടതായി വരാം, എന്നാൽ ഒരു പൊതുവായDataFetchingComponent
-ൽ നിന്ന് അവ ഇൻഹെറിറ്റ് ചെയ്യുന്നത് അർത്ഥശൂന്യമാണ്. - Prop-Drilling Hell: ആഴത്തിലുള്ള ഇൻഹെറിറ്റൻസ് ശൃംഖലയിൽ, ഒരു ടോപ്പ്-ലെവൽ കോമ്പണന്റിൽ നിന്ന് ആഴത്തിൽ നെസ്റ്റ് ചെയ്ത ചൈൽഡിലേക്ക് പ്രോപ്പുകൾ പാസ് ചെയ്യുന്നത് ബുദ്ധിമുട്ടാണ്. ഉപയോഗിക്കാത്ത പ്രോപ്പുകൾ പോലും ഉപയോഗിക്കാത്ത ഇടത്തരം കോമ്പണന്റുകളിലൂടെ നിങ്ങൾക്ക് പാസ് ചെയ്യേണ്ടി വന്നേക്കാം, ഇത് ആശയക്കുഴപ്പമുണ്ടാക്കുന്നതും വികൃതവുമായ കോഡിലേക്ക് നയിക്കുന്നു.
- "ഗോറില്ല-ബനാന പ്രശ്നം": OOP വിദഗ്ധൻ ജോ ആംസ്ട്രോങ്ങിൻ്റെ പ്രശസ്തമായ ഒരു ഉദ്ധരണി ഈ പ്രശ്നം കൃത്യമായി വിവരിക്കുന്നു: "നിങ്ങൾക്ക് ഒരു ബനാന വേണമായിരുന്നു, പക്ഷെ നിങ്ങൾക്ക് ബനാന പിടിച്ചിരിക്കുന്ന ഒരു ഗോറില്ലയും മുഴുവൻ വനവും കിട്ടി." ഇൻഹെറിറ്റൻസിലൂടെ, നിങ്ങൾക്ക് ആവശ്യമുള്ള പ്രവർത്തനക്ഷമതയുടെ ഭാഗം ലഭിക്കുകയില്ല; മുഴുവൻ സൂപ്പർക്ലാസും അതോടൊപ്പം കൊണ്ടുപോകാൻ നിങ്ങൾക്ക് നിർബന്ധിതരാകുന്നു.
ഈ പ്രശ്നങ്ങൾ കാരണം, റിയാക്റ്റ് ടീം ലൈബ്രറിയെ കൂടുതൽ അയവുള്ളതും ശക്തവുമായ ഒരു മാതൃകയിൽ രൂപകൽപ്പന ചെയ്തു: കോമ്പോസിഷൻ.
റിയാക്റ്റ് രീതി സ്വീകരിക്കുക: കോമ്പോസിഷൻ്റെ ശക്തി
കോമ്പോസിഷൻ എന്നത് ഒരു ഡിസൈൻ തത്വമാണ്, ഇത് 'has-a' അല്ലെങ്കിൽ 'uses-a' ബന്ധത്തെ അനുകൂലിക്കുന്നു. ഒരു കോമ്പണന്റ് മറ്റൊരു കോമ്പണന്റ് ആകുന്നതിന് പകരം, അത് മറ്റ് കോമ്പണന്റുകളെ കൊണ്ടുപോകുന്നു അല്ലെങ്കിൽ അവയുടെ പ്രവർത്തനക്ഷമത ഉപയോഗിക്കുന്നു. കോമ്പണന്റുകൾ ബിൽഡിംഗ് ബ്ലോക്കുകളായി പരിഗണിക്കപ്പെടുന്നു - ലെഗോ ഇഷ്ടികകൾ പോലെ - കർശനമായ ശ്രേണിയിൽ ലോക്ക് ചെയ്യാതെ സങ്കീർണ്ണമായ UI-കൾ സൃഷ്ടിക്കാൻ വിവിധ രീതികളിൽ അവ കൂട്ടിച്ചേർക്കാൻ കഴിയും.
റിയാക്റ്റിൻ്റെ കോമ്പോസിഷണൽ മോഡൽ വളരെ ബഹുമുഖമാണ്, ഇത് പല പ്രധാന പാറ്റേണുകളിലും പ്രകടമാകുന്നു. ഏറ്റവും അടിസ്ഥാന തലത്തിൽ നിന്ന് ഏറ്റവും ആധുനികവും ശക്തവുമായവ വരെ അവ പരിശോധിക്കാം.
വിദ്യ 1: `props.children` ഉപയോഗിച്ച് കണ്ടെയ്ൻമെൻ്റ്
കോമ്പോസിഷൻ്റെ ഏറ്റവും ലളിതമായ രൂപം കണ്ടെയ്ൻമെൻ്റ് ആണ്. ഇവിടെ ഒരു കോമ്പണന്റ് ഒരു സാധാരണ കണ്ടെയ്നർ അല്ലെങ്കിൽ 'ബോക്സ്' ആയി പ്രവർത്തിക്കുന്നു, അതിൻ്റെ ഉള്ളടക്കം ഒരു പാരൻ്റ് കോമ്പണന്റിൽ നിന്ന് പാസ് ചെയ്യുന്നു. റിയാക്റ്റിന് ഇതിനായി ഒരു പ്രത്യേക, ബിൽറ്റ്-ഇൻ പ്രോപ്പ് ഉണ്ട്: 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>Welcome!</h1>
<p>This content is inside a Card component.</p>
</Card>
<Card>
<img src="/path/to/image.jpg" alt="An example image" />
<p>This is an image card.</p>
</Card>
</div>
);
}
ഇവിടെ, Card
കോമ്പണന്റ് അത് എന്തു വഹിക്കുന്നു എന്ന് അറിയില്ല അല്ലെങ്കിൽ ശ്രദ്ധിക്കുന്നില്ല. അത് ലളിതമായ റാപ്പറുകളുടെ സ്റ്റൈലിംഗ് നൽകുന്നു. തുറക്കുന്നതും അടയ്ക്കുന്നതുമായ <Card>
ടാഗുകൾക്കിടയിലുള്ള ഉള്ളടക്കം സ്വയമേവ props.children
ആയി പാസ് ചെയ്യപ്പെടുന്നു. ഇത് ഡീകപ്ലിംഗിൻ്റെയും പുനരുപയോഗത്തിൻ്റെയും ഒരു മനോഹരമായ ഉദാഹരണമാണ്.
വിദ്യ 2: പ്രോപ്പുകൾ ഉപയോഗിച്ച് സ്പെഷ്യലൈസേഷൻ
ചിലപ്പോൾ, ഒരു കോമ്പണൻ്റിന് മറ്റ് കോമ്പണന്റുകളാൽ നിറയ്ക്കേണ്ട ഒന്നിലധികം 'ഹോളുകൾ' ആവശ്യമായി വരും. നിങ്ങൾക്ക് props.children
ഉപയോഗിക്കാമെങ്കിലും, പ്രോപ്പുകൾ വഴി കോമ്പണന്റുകളെ പാസ് ചെയ്യുന്ന കൂടുതൽ വ്യക്തവും ഘടനാപരവുമായ മാർഗ്ഗം സ്പെഷ്യലൈസേഷൻ എന്ന് വിളിക്കപ്പെടുന്നു.
ഒരു `Modal` കോമ്പണന്റ് പരിഗണിക്കൂ. ഒരു മോഡലിന് സാധാരണയായി ഒരു ടൈറ്റിൽ വിഭാഗം, ഒരു കണ്ടൻ്റ് വിഭാഗം, ഒരു പ്രവർത്തന വിഭാഗം ( "Confirm" അല്ലെങ്കിൽ "Cancel" പോലുള്ള ബട്ടണുകൾ) എന്നിവയുണ്ട്. ഈ വിഭാഗങ്ങളെ പ്രോപ്പുകളായി സ്വീകരിക്കാൻ ഞങ്ങളുടെ `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>Confirm Action</h2>;
const confirmationBody = <p>Are you sure you want to proceed with this action?</p>;
const confirmationActions = (
<div>
<button>Confirm</button>
<button>Cancel</button>
</div>
);
return (
<Modal
title={confirmationTitle}
body={confirmationBody}
actions={confirmationActions}
/>
);
}
ഈ ഉദാഹരണത്തിൽ, Modal
ഒരു ഉയർന്ന പുനരുപയോഗിക്കാവുന്ന ലേഔട്ട് കോമ്പണന്റ് ആണ്. അതിൻ്റെ `title`, `body`, `actions` എന്നിവയ്ക്കായി പ്രത്യേക JSX ഘടകങ്ങൾ പാസ് ചെയ്തുകൊണ്ട് ഞങ്ങൾ അത് സ്പെഷ്യലൈസ് ചെയ്യുന്നു. ഇത് `ConfirmationModal` ഉം `WarningModal` ഉം സബ്ക്ലാസുകൾ സൃഷ്ടിക്കുന്നതിനേക്കാൾ വളരെ അയവുള്ളതാണ്. ആവശ്യമെങ്കിൽ വ്യത്യസ്ത ഉള്ളടക്കങ്ങളുമായി ഞങ്ങൾ Modal
കോമ്പോസ് ചെയ്യുന്നു.
വിദ്യ 3: ഹയർ-ഓർഡർ കോമ്പണന്റുകൾ (HOCs)
ഡാറ്റാ ഫെച്ചിംഗ്, ഓതൻ്റിക്കേഷൻ, അല്ലെങ്കിൽ ലോഗിംഗ് പോലുള്ള UI ഇതര ലോജിക് പങ്കിടാൻ, റിയാക്റ്റ് ഡെവലപ്പർമാർ ചരിത്രപരമായി ഹയർ-ഓർഡർ കോമ്പണന്റുകൾ (HOCs) എന്ന പാറ്റേൺ സ്വീകരിച്ചിരുന്നു. ആധുനിക റിയാക്റ്റിൽ പ്രധാനമായും ഹുക്ക്സ് മാറ്റിസ്ഥാപിച്ചെങ്കിലും, റിയാക്റ്റിൻ്റെ കോമ്പോസിഷൻ്റെ കഥയിലെ ഒരു പ്രധാന പരിണാമ ഘട്ടത്തെ പ്രതിനിധീകരിക്കുന്നതിനാൽ അവ മനസ്സിലാക്കേണ്ടത് അത്യാവശ്യമാണ്, കൂടാതെ നിരവധി കോഡ്ബേസുകളിൽ ഇവ ഇപ്പോഴും നിലവിലുണ്ട്.
ഒരു HOC എന്നത് ഒരു കോമ്പണന്റ് ഒരു ആർഗ്യുമെൻ്റായി എടുക്കുകയും ഒരു പുതിയ, മെച്ചപ്പെടുത്തിയ കോമ്പണന്റ് റിട്ടേൺ ചെയ്യുകയും ചെയ്യുന്ന ഒരു ഫംഗ്ഷനാണ്.
ഒരു കോമ്പണൻ്റിൻ്റെ പ്രോപ്പുകൾ അപ്ഡേറ്റ് ചെയ്യുമ്പോൾ അവ ലോഗ് ചെയ്യുന്ന `withLogger` എന്ന് വിളിക്കുന്ന ഒരു HOC സൃഷ്ടിക്കാം. ഇത് ഡീബഗ്ഗിംഗിന് ഉപയോഗപ്രദമാണ്.
// withLogger.js - HOC
import React, { useEffect } from 'react';
function withLogger(WrappedComponent) {
// ഇത് ഒരു പുതിയ കോമ്പണന്റ് റിട്ടേൺ ചെയ്യുന്നു...
return function EnhancedComponent(props) {
useEffect(() => {
console.log('Component updated with new props:', props);
}, [props]);
// ... യഥാർത്ഥ പ്രോപ്പുകളുള്ള യഥാർത്ഥ കോമ്പണന്റ് റെൻഡർ ചെയ്യുന്നു.
return <WrappedComponent {...props} />;
};
}
// MyComponent.js - മെച്ചപ്പെടുത്തേണ്ട കോമ്പണന്റ്
function MyComponent({ name, age }) {
return (
<div>
<h1>Hello, {name}!</h1>
<p>You are {age} years old.</p>
</div>
);
}
// മെച്ചപ്പെടുത്തിയ കോമ്പണന്റ് എക്സ്പോർട്ട് ചെയ്യുന്നു
export default withLogger(MyComponent);
withLogger
ഫംഗ്ഷൻ MyComponent
-നെ പൊതിയുന്നു, MyComponent
-ൻ്റെ ആന്തരിക കോഡ് മാറ്റാതെ അതിന് പുതിയ ലോഗിംഗ് കഴിവുകൾ നൽകുന്നു. അതേ ലോഗിംഗ് ഫീച്ചർ നൽകുന്നതിനായി ഏതെങ്കിലും മറ്റ് കോമ്പണന്റിൽ ഈ HOC പ്രയോഗിക്കാൻ ഞങ്ങൾക്ക് കഴിയും.
HOC-കളുമായുള്ള പ്രശ്നങ്ങൾ:
- റാപ്പർ ഹെൽ: ഒരൊറ്റ കോമ്പണന്റിൽ ഒന്നിലധികം HOC-കൾ പ്രയോഗിക്കുന്നത് റിയാക്റ്റ് ഡെവ്ടൂൾസിൽ ആഴത്തിൽ നെസ്റ്റ് ചെയ്ത കോമ്പണന്റുകളിലേക്ക് നയിച്ചേക്കാം (ഉദാ., `withAuth(withRouter(withLogger(MyComponent)))`), ഡീബഗ്ഗിംഗ് ബുദ്ധിമുട്ടാക്കുന്നു.
- പ്രോപ്പ് നെയിം കോളിഷൻസ്: ഒരു HOC ഒരു പ്രോപ്പ് നൽകുകയാണെങ്കിൽ (ഉദാ., `data`) അത് ఇప్పటికే പൊതിഞ്ഞ കോമ്പണൻ്റ് ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, അത് ആകസ്മികമായി ഓവർറൈഡ് ചെയ്യപ്പെടാം.
- അവ്യക്തമായ ലോജിക്: കോമ്പണൻ്റിൻ്റെ കോഡിൽ നിന്ന് അതിൻ്റെ പ്രോപ്പുകൾ എവിടെ നിന്ന് വരുന്നു എന്ന് എപ്പോഴും വ്യക്തമായിരിക്കില്ല. ലോജിക് HOC-ൽ മറഞ്ഞിരിക്കുന്നു.
വിദ്യ 4: റെൻഡർ പ്രോപ്സ്
HOC-കളുടെ ചില പ്രശ്നങ്ങൾക്ക് പരിഹാരമായി റെൻഡർ പ്രോപ് പാറ്റേൺ ഉയർന്നുവന്നു. ഇത് ലോജിക് പങ്കിടാൻ കൂടുതൽ വ്യക്തമായ ഒരു മാർഗ്ഗം നൽകുന്നു.
ഒരു റെൻഡർ പ്രോപ്പ് ഉള്ള കോമ്പണന്റ് ഒരു പ്രോപ്പ് (സാധാരണയായി `render` എന്ന് വിളിക്കപ്പെടുന്നു) ആയി ഒരു ഫംഗ്ഷൻ എടുക്കുകയും അതിലേക്ക് സ്റ്റേറ്റോ ലോജിക്കോ ആർഗ്യുമെൻ്റുകളായി പാസ് ചെയ്തുകൊണ്ട് റെൻഡർ ചെയ്യേണ്ടത് എന്താണെന്ന് നിർണ്ണയിക്കാൻ ആ ഫംഗ്ഷൻ വിളിക്കുകയും ചെയ്യുന്നു.
മൗസിൻ്റെ X, Y കോർഡിനേറ്റുകൾ ട്രാക്ക് ചെയ്യുകയും അവ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്ന ഏത് കോമ്പണൻ്റിനും ലഭ്യമാക്കുകയും ചെയ്യുന്ന ഒരു `MouseTracker` കോമ്പണന്റ് സൃഷ്ടിക്കാം.
// 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>Move your mouse around!</h1>
<MouseTracker
render={mousePosition => (
<p>The current mouse position is ({mousePosition.x}, {mousePosition.y})</p>
)}
/>
</div>
);
}
ഇവിടെ, MouseTracker
മൗസ് ചലനം ട്രാക്ക് ചെയ്യുന്നതിനുള്ള എല്ലാ ലോജിക്കും എൻക്യാപ്സുലേറ്റ് ചെയ്യുന്നു. ഇത് സ്വയം ഒന്നും റെൻഡർ ചെയ്യുന്നില്ല. പകരം, അത് അതിൻ്റെ `render` പ്രോപ്പിലേക്ക് റെൻഡറിംഗ് ലോജിക് ഏൽപ്പിക്കുന്നു. നിങ്ങൾക്ക് `mousePosition` ഡാറ്റ എവിടെ നിന്ന് വരുന്നു എന്ന് JSX-ൽ തന്നെ കാണാൻ കഴിയുന്നതിനാൽ ഇത് HOC-കളെക്കാൾ വ്യക്തമാണ്.
children
പ്രോപ്പ് ഒരു ഫംഗ്ഷനായും ഉപയോഗിക്കാം, ഇത് ഈ പാറ്റേണിൻ്റെ ഒരു സാധാരണയും മനോഹരവുമായ വേരിയൻ്റ് ആണ്:
// children ഒരു ഫംഗ്ഷനായി ഉപയോഗിക്കുന്നു
<MouseTracker>
{mousePosition => (
<p>The current mouse position is ({mousePosition.x}, {mousePosition.y})</p>
)}
</MouseTracker>
വിദ്യ 5: ഹുക്ക്സ് (ആധുനികവും മുൻഗണന നൽകുന്നതുമായ സമീപനം)
റിയാക്റ്റ് 16.8-ൽ അവതരിപ്പിച്ച ഹുക്ക്സ്, റിയാക്റ്റ് കോമ്പണന്റുകൾ ഞങ്ങൾ എങ്ങനെ എഴുതുന്നു എന്നത് വിപ്ലവകരമാക്കി. അവ ഫംഗ്ഷണൽ കോമ്പണന്റുകളിൽ സ്റ്റേറ്റും മറ്റ് റിയാക്റ്റ് ഫീച്ചറുകളും ഉപയോഗിക്കാൻ നിങ്ങളെ അനുവദിക്കുന്നു. ഏറ്റവും പ്രധാനമായി, കസ്റ്റം ഹുക്ക്സ് കോമ്പണന്റുകൾക്കിടയിൽ സ്റ്റേറ്റ്ഫുൾ ലോജിക് പങ്കിടുന്നതിന് ഏറ്റവും മനോഹരവും നേരിട്ടുള്ളതുമായ പരിഹാരം നൽകുന്നു.
HOC-കളുടെയും റെൻഡർ പ്രോപ്സുകളുടെയും പ്രശ്നങ്ങൾ ഹുക്ക്സ് കൂടുതൽ വൃത്തിയുള്ള രീതിയിൽ പരിഹരിക്കുന്നു. ഞങ്ങളുടെ `MouseTracker` ഉദാഹരണം `useMousePosition` എന്ന് വിളിക്കുന്ന ഒരു കസ്റ്റം ഹുക്കിലേക്ക് refactor ചെയ്യാം.
// 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>
The mouse position is ({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`) പൂർണ്ണമായും ഡീകപ്പിൾ ചെയ്തിരിക്കുന്നു, ഏത് കോമ്പണൻ്റിനും വളരെ വ്യക്തമായ ഒരു കോഡ് ലൈനിലൂടെ ആ സ്റ്റേറ്റ്ഫുൾ ലോജിക്കിലേക്ക് 'ഹുക്ക്' ചെയ്യാൻ കഴിയും. കസ്റ്റം ഹുക്ക്സ് ആധുനിക റിയാക്റ്റിലെ കോമ്പോസിഷൻ്റെ അന്തിമ പ്രകടനമാണ്, നിങ്ങളുടെ സ്വന്തം പുനരുപയോഗിക്കാവുന്ന ലോജിക് ബ്ലോക്കുകളുടെ ഒരു ലൈബ്രറി നിർമ്മിക്കാൻ നിങ്ങളെ ഇത് അനുവദിക്കുന്നു.
ഒരു വേഗത്തിലുള്ള താരതമ്യം: റിയാക്റ്റിലെ കോമ്പോസിഷൻ വേഴ്സസ് ഇൻഹെറിറ്റൻസ്
റിയാക്റ്റ് സന്ദർഭത്തിലെ പ്രധാന വ്യത്യാസങ്ങൾ സംഗ്രഹിക്കാൻ, ഇതാ ഒരു നേരിട്ടുള്ള താരതമ്യം:
വശം | ഇൻഹെറിറ്റൻസ് (റിയാക്റ്റിൽ വിരുദ്ധ പാറ്റേൺ) | കോമ്പോസിഷൻ (റിയാക്റ്റിൽ മുൻഗണന) |
---|---|---|
ബന്ധം | 'is-a' ബന്ധം. ഒരു സ്പെഷ്യലൈസ്ഡ് കോമ്പണന്റ് ഒരു ബേസ് കോമ്പണൻ്റിൻ്റെ ഒരു പതിപ്പ് ആണ്. | 'has-a' അല്ലെങ്കിൽ 'uses-a' ബന്ധം. ഒരു സങ്കീർണ്ണ കോമ്പണന്റ് ചെറിയ കോമ്പണന്റുകളെ കൊണ്ടുപോകുന്നു അല്ലെങ്കിൽ പങ്കിട്ട ലോജിക് ഉപയോഗിക്കുന്നു. |
ബന്ധിതത്വം (Coupling) | ഉയർന്നത്. ചൈൽഡ് കോമ്പണന്റുകൾ അവയുടെ പാരൻ്റിൻ്റെ പ്രവർത്തനങ്ങളുമായി കർശനമായി ബന്ധിതമാകുന്നു. | കുറഞ്ഞത്. കോമ്പണന്റുകൾ സ്വതന്ത്രമാണ്, പരിപാലനം കൂടാതെ വ്യത്യസ്ത സന്ദർഭങ്ങളിൽ പുനരുപയോഗിക്കാനും കഴിയും. |
അയവ് (Flexibility) | കുറഞ്ഞത്. കർശനമായ, ക്ലാസ് അധിഷ്ഠിത ശ്രേണികൾ വിവിധ കോമ്പണന്റ് ട്രീകളിലുടനീളം ലോജിക് പങ്കിടുന്നത് ബുദ്ധിമുട്ടാക്കുന്നു. | ഉയർന്നത്. ലോജിക്കോ UI-യോ ഇഷ്ടാനുസരണം കൂട്ടിച്ചേർക്കാനും പുനരുപയോഗിക്കാനും കഴിയും, ബിൽഡിംഗ് ബ്ലോക്കുകൾ പോലെ. |
കോഡ് പുനരുപയോഗം | മുൻകൂട്ടി നിശ്ചയിച്ച ശ്രേണിയിലേക്ക് പരിമിതപ്പെടുത്തിയിരിക്കുന്നു. നിങ്ങൾക്ക് "ബനാന" മാത്രം ആവശ്യമുള്ളപ്പോൾ നിങ്ങൾ മുഴുവൻ "ഗോറില്ലയും" ലഭിക്കുന്നു. | അടിപൊളി. ചെറിയ, ശ്രദ്ധ കേന്ദ്രീകരിച്ച കോമ്പണന്റുകളും ഹുക്ക്സും മുഴുവൻ ആപ്ലിക്കേഷനിലുടനീളം ഉപയോഗിക്കാം. |
റിയാക്റ്റ് രീതി | ഔദ്യോഗിക റിയാക്റ്റ് ടീം നിരുത്സാഹപ്പെടുത്തുന്നു. | റിയാക്റ്റ് ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിനുള്ള ശുപാർശ ചെയ്തതും രീതിശാസ്ത്രപരവുമായ സമീപനം. |
ഉപസംഹാരം: കോമ്പോസിഷനിൽ ചിന്തിക്കുക
കോമ്പോസിഷനും ഇൻഹെറിറ്റൻസിനും ഇടയിലുള്ള ചർച്ച സോഫ്റ്റ്വെയർ ഡിസൈനിലെ ഒരു അടിസ്ഥാന വിഷയമാണ്. ഇൻഹെറിറ്റൻസിന് ക്ലാസിക്കൽ OOP-യിൽ അതിൻ്റേതായ സ്ഥാനമുണ്ടെങ്കിലും, UI ഡെവലപ്മെൻ്റിൻ്റെ ഡൈനാമിക്, കോമ്പണന്റ് അധിഷ്ഠിത സ്വഭാവം റിയാക്റ്റിന് അനുയോജ്യമല്ലാത്തതാക്കുന്നു. ലൈബ്രറി അടിസ്ഥാനപരമായി കോമ്പോസിഷൻ സ്വീകരിക്കുന്നതിനായി രൂപകൽപ്പന ചെയ്തതാണ്.
കോമ്പോസിഷനെ അനുകൂലിക്കുന്നതിലൂടെ, നിങ്ങൾ നേടുന്നു:
- അയവ്: ആവശ്യമുള്ളതുപോലെ UI-യും ലോജിക്കോ മിക്സ് ചെയ്യാനും മാച്ച് ചെയ്യാനുമുള്ള കഴിവ്.
- പരിപാലനം: ലൂസ്ലി കപ്പിൾ ചെയ്ത കോമ്പണന്റുകൾ ഒറ്റയ്ക്ക് മനസ്സിലാക്കാനും പരീക്ഷിക്കാനും റീഫാക്ടർ ചെയ്യാനും എളുപ്പമാണ്.
- സ്കേലബിലിറ്റി: കോമ്പോസിഷണൽ ചിന്താഗതി ചെറിയ, പുനരുപയോഗിക്കാവുന്ന കോമ്പണന്റുകളുടെയും ഹുക്കുകളുടെയും ഒരു ഡിസൈൻ സിസ്റ്റം സൃഷ്ടിക്കാൻ പ്രോത്സാഹിപ്പിക്കുന്നു, അത് കാര്യക്ഷമമായി വലിയ, സങ്കീർണ്ണമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ ഉപയോഗിക്കാം.
ഒരു ലോകോത്തര റിയാക്റ്റ് ഡെവലപ്പർ എന്ന നിലയിൽ, കോമ്പോസിഷൻ മാസ്റ്റർ ചെയ്യുന്നത് മികച്ച സമ്പ്രദായങ്ങൾ പിന്തുടരുക എന്നതിലുപരിയാണ്—ഇത് റിയാക്റ്റിനെ അത്രയും ശക്തവും ഉൽപ്പാദനക്ഷമവുമായ ഉപകരണമാക്കുന്ന കോർ ഫിലോസഫി മനസ്സിലാക്കുക എന്നതാണ്. ചെറിയ, ശ്രദ്ധ കേന്ദ്രീകരിച്ച കോമ്പണന്റുകൾ സൃഷ്ടിച്ച് തുടങ്ങുക. സാധാരണ കണ്ടെയ്നറുകൾക്കായി props.children
ഉപയോഗിക്കുക, സ്പെഷ്യലൈസേഷനായി പ്രോപ്പുകൾ ഉപയോഗിക്കുക. ലോജിക് പങ്കിടാൻ, ആദ്യം കസ്റ്റം ഹുക്ക്സ് ഉപയോഗിക്കുക. കോമ്പോസിഷനിൽ ചിന്തിക്കുന്നതിലൂടെ, കാലത്തെ അതിജീവിക്കുന്ന മനോഹരവും ശക്തവും സ്കേലബിളുമായ റിയാക്റ്റ് ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിൻ്റെ നല്ല വഴിയിൽ നിങ്ങൾ ആയിരിക്കും.