React komponent arxitekturasiga chuqur kirish, kompozitsiya va vorislikni taqqoslash. React nima uchun kompozitsiyani afzal ko'rishini bilib oling va masshtablanuvchan, qayta ishlatiladigan komponentlar yaratish uchun HOC, Render Props va Hooklar kabi naqshlarni o'rganing.
React Komponent Arxitekturasi: Nima uchun Kompozitsiya Vorislikdan Ustun Turadi
Dasturiy ta'minotni ishlab chiqish dunyosida arxitektura eng muhim narsadir. Kodimizni qanday tuzishimiz uning masshtablanuvchanligi, qo'llab-quvvatlanuvchanligi va qayta ishlatilishini belgilaydi. React bilan ishlaydigan dasturchilar uchun eng fundamental arxitekturaviy qarorlardan biri komponentlar o'rtasida mantiq va UI'ni qanday ulashishga bog'liq. Bu bizni obyektga yo'naltirilgan dasturlashdagi klassik munozaraga olib keladi, u React'ning komponentlarga asoslangan dunyosi uchun qayta tasavvur qilingan: Kompozitsiya vs. Vorislik.
Agar siz Java yoki C++ kabi klassik obyektga yo'naltirilgan dasturlash tillaridan kelgan bo'lsangiz, vorislik siz uchun tabiiy tanlovdek tuyulishi mumkin. Bu 'is-a' munosabatlarini yaratish uchun kuchli tushuncha. Biroq, rasmiy React hujjatlarida aniq va qat'iy tavsiya berilgan: "Facebook'da biz minglab komponentlarda React'dan foydalanamiz va komponentlar vorisligi ierarxiyasini yaratishni tavsiya qiladigan birorta holat topmadik."
Ushbu maqola ushbu arxitekturaviy tanlovni har tomonlama o'rganib chiqadi. Biz React kontekstida vorislik va kompozitsiya nima ekanligini tushuntirib beramiz, nima uchun kompozitsiya idiomatik va ustun yondashuv ekanligini ko'rsatamiz va Yuqori Tartibli Komponentlardan tortib zamonaviy Hooklargacha bo'lgan kuchli naqshlarni o'rganamiz — bu naqshlar kompozitsiyani global auditoriya uchun mustahkam va moslashuvchan dasturlar yaratishda dasturchining eng yaxshi do'stiga aylantiradi.
Eski Gvardiyani Tushunish: Vorislik Nima?
Vorislik - Obyektga Yo'naltirilgan Dasturlashning (OYD) asosiy ustunlaridan biridir. U yangi sinfga (quyi sinf yoki bola) mavjud sinfning (yuqori sinf yoki ota-ona) xususiyatlari va metodlarini olish imkonini beradi. Bu qattiq bog'langan 'is-a' munosabatini yaratadi. Masalan, GoldenRetriever
bu Dog
, u esa o'z navbatida Animal
.
Vorislikning React'dan Tashqari Konteksti
Keling, tushunchani mustahkamlash uchun oddiy JavaScript sinfi misolini ko'rib chiqaylik:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Ota-ona konstruktorini chaqiradi
this.breed = breed;
}
speak() { // Ota-ona metodini qayta yozadi
console.log(`${this.name} barks.`);
}
fetch() {
console.log(`${this.name} is fetching the ball!`);
}
}
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); // Natija: "Buddy barks."
myDog.fetch(); // Natija: "Buddy is fetching the ball!"
Ushbu modelda `Dog` sinfi `Animal`dan `name` xususiyati va `speak` metodini avtomatik ravishda oladi. U shuningdek o'zining metodlarini qo'shishi (`fetch`) va mavjudlarini qayta yozishi mumkin. Bu qat'iy ierarxiyani yaratadi.
Nima uchun Vorislik React'da Oqsab Qoladi
Ushbu 'is-a' modeli ba'zi ma'lumotlar tuzilmalari uchun ishlasa-da, React'dagi UI komponentlariga qo'llanilganda jiddiy muammolarni keltirib chiqaradi:
- Qattiq bog'liqlik: Komponent asosiy komponentdan vorislik olganda, u o'z ota-onasining implementatsiyasiga qattiq bog'lanib qoladi. Asosiy komponentdagi o'zgarish zanjir bo'ylab bir nechta quyi komponentlarni kutilmaganda buzishi mumkin. Bu refaktoring va texnik xizmat ko'rsatishni mo'rt jarayonga aylantiradi.
- Moslashuvchan bo'lmagan mantiqni ulashish: Agar siz ma'lumotlarni yuklash kabi ma'lum bir funksionallikni bir xil 'is-a' ierarxiyasiga to'g'ri kelmaydigan komponentlar bilan ulashmoqchi bo'lsangiz-chi? Masalan, `UserProfile` va `ProductList` ikkalasi ham ma'lumotlarni yuklashi kerak bo'lishi mumkin, lekin ularning umumiy `DataFetchingComponent`dan vorislik olishi mantiqqa to'g'ri kelmaydi.
- Prop-Drilling Do'zaxi: Chuqur vorislik zanjirida proplarni yuqori darajadagi komponentdan chuqur joylashgan quyi komponentga uzatish qiyinlashadi. Siz proplarni hatto ulardan foydalanmaydigan oraliq komponentlar orqali uzatishingizga to'g'ri kelishi mumkin, bu esa chalkash va keraksiz kodga olib keladi.
- "Gorilla-Banan Muammosi": OYD mutaxassisi Joe Armstrongning mashhur iqtibosi bu masalani mukammal tasvirlaydi: "Siz banan xohlagan edingiz, lekin sizga bananni ushlab turgan gorilla va butun o'rmon berildi." Vorislik bilan siz shunchaki o'zingiz xohlagan funksionallik qismini ololmaysiz; siz butun yuqori sinfni o'zi bilan birga olib kelishga majbur bo'lasiz.
Ushbu muammolar tufayli React jamoasi kutubxonani yanada moslashuvchan va kuchli paradigma atrofida ishlab chiqdi: kompozitsiya.
React Yo'lini Qabul Qilish: Kompozitsiyaning Kuchi
Kompozitsiya - bu 'has-a' yoki 'uses-a' munosabatini afzal ko'radigan dizayn tamoyilidir. Komponent boshqa bir komponent bo'lish o'rniga, u boshqa komponentlarga ega bo'ladi yoki ularning funksionalligidan foydalanadi. Komponentlar qurilish bloklari — LEGO g'ishtlari kabi — qat'iy ierarxiyaga bog'lanib qolmasdan murakkab UI'lar yaratish uchun turli usullarda birlashtirilishi mumkin bo'lgan elementlar sifatida qaraladi.
React'ning kompozitsion modeli nihoyatda ko'p qirrali bo'lib, u bir nechta asosiy naqshlarda namoyon bo'ladi. Keling, ularni eng oddiysidan eng zamonaviy va kuchlisigacha ko'rib chiqamiz.
1-Usul: `props.children` bilan Qamrab Olish
Kompozitsiyaning eng oddiy shakli bu qamrab olishdir. Bunda komponent umumiy konteyner yoki 'quti' vazifasini bajaradi va uning tarkibi ota-ona komponentdan uzatiladi. React'da buning uchun maxsus, o'rnatilgan prop mavjud: `props.children`.
Tasavvur qiling, sizga har qanday tarkibni doimiy chegara va soya bilan o'rab turadigan `Card` komponenti kerak. Vorislik orqali `TextCard`, `ImageCard` va `ProfileCard` variantlarini yaratish o'rniga, siz bitta umumiy `Card` komponentini yaratasiz.
// Card.js - Umumiy konteyner komponenti
function Card(props) {
return (
<div className="card">
{props.children}
</div>
);
}
// App.js - Card komponentidan foydalanish
function App() {
return (
<div>
<Card>
<h1>Xush kelibsiz!</h1>
<p>Ushbu tarkib Card komponenti ichida.</p>
</Card>
<Card>
<img src="/path/to/image.jpg" alt="Misol uchun rasm" />
<p>Bu rasm kartasi.</p>
</Card>
</div>
);
}
Bu yerda `Card` komponenti o'z ichida nima borligini bilmaydi va bunga ahamiyat bermaydi. U shunchaki o'rab turuvchi stillarni ta'minlaydi. Ochiluvchi va yopiluvchi `<Card>` teglari orasidagi tarkib avtomatik ravishda `props.children` sifatida uzatiladi. Bu bog'liqlikni yo'qotish va qayta ishlatishning go'zal namunasidir.
2-Usul: Proplar Bilan Ixtisoslashtirish
Ba'zan, komponent boshqa komponentlar tomonidan to'ldirilishi kerak bo'lgan bir nechta 'bo'shliqlar'ga ehtiyoj sezadi. `props.children`dan foydalanish mumkin bo'lsa-da, komponentlarni oddiy proplar sifatida uzatish yanada aniq va tizimli usuldir. Ushbu naqsh ko'pincha ixtisoslashtirish deb ataladi.
`Modal` komponentini ko'rib chiqaylik. Modal odatda sarlavha qismi, tarkib qismi va harakatlar qismiga (masalan, "Tasdiqlash" yoki "Bekor qilish" tugmalari bilan) ega bo'ladi. Biz `Modal`imizni ushbu qismlarni prop sifatida qabul qiladigan qilib loyihalashimiz mumkin.
// Modal.js - Yanada ixtisoslashgan konteyner
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'dan maxsus komponentlar bilan foydalanish
function App() {
const confirmationTitle = <h2>Harakatni Tasdiqlash</h2>;
const confirmationBody = <p>Ushbu harakatni davom ettirishga ishonchingiz komilmi?</p>;
const confirmationActions = (
<div>
<button>Tasdiqlash</button>
<button>Bekor qilish</button>
</div>
);
return (
<Modal
title={confirmationTitle}
body={confirmationBody}
actions={confirmationActions}
/>
);
}
Ushbu misolda `Modal` yuqori darajada qayta ishlatiladigan maket komponentidir. Biz uning `title`, `body` va `actions` uchun maxsus JSX elementlarini uzatish orqali uni ixtisoslashtiramiz. Bu `ConfirmationModal` va `WarningModal` quyi sinflarini yaratishdan ancha moslashuvchanroqdir. Biz shunchaki `Modal`ni kerak bo'lganda turli tarkib bilan kompozitsiya qilamiz.
3-Usul: Yuqori Tartibli Komponentlar (HOCs)
Ma'lumotlarni yuklash, autentifikatsiya yoki log yozish kabi UI'ga oid bo'lmagan mantiqni ulashish uchun React dasturchilari tarixan Yuqori Tartibli Komponentlar (HOCs) deb nomlangan naqshga murojaat qilishgan. Garchi zamonaviy React'da asosan Hooklar bilan almashtirilgan bo'lsa-da, ularni tushunish juda muhim, chunki ular React'ning kompozitsiya tarixidagi asosiy evolyutsion qadamni ifodalaydi va hali ham ko'plab kod bazalarida mavjud.
HOC - bu komponentni argument sifatida qabul qilib, yangi, takomillashtirilgan komponentni qaytaradigan funksiya.
Keling, `withLogger` deb nomlangan HOC yaratamiz, u har safar yangilanganda komponentning proplarini logga yozadi. Bu disk raskadrovka uchun foydalidir.
// withLogger.js - HOC
import React, { useEffect } from 'react';
function withLogger(WrappedComponent) {
// U yangi komponent qaytaradi...
return function EnhancedComponent(props) {
useEffect(() => {
console.log('Komponent yangi proplar bilan yangilandi:', props);
}, [props]);
// ... u asl komponentni asl proplar bilan render qiladi.
return <WrappedComponent {...props} />;
};
}
// MyComponent.js - Takomillashtiriladigan komponent
function MyComponent({ name, age }) {
return (
<div>
<h1>Salom, {name}!</h1>
<p>Siz {age} yoshdasiz.</p>
</div>
);
}
// Takomillashtirilgan komponentni eksport qilish
export default withLogger(MyComponent);
`withLogger` funksiyasi `MyComponent`ni o'rab olib, `MyComponent`ning ichki kodini o'zgartirmasdan unga yangi log yozish imkoniyatini beradi. Biz ushbu HOC'ni boshqa har qanday komponentga qo'llab, unga ham xuddi shunday log yozish xususiyatini berishimiz mumkin edi.
HOC'lar bilan bog'liq qiyinchiliklar:
- Wrapper Do'zaxi: Bitta komponentga bir nechta HOC'larni qo'llash React DevTools'da chuqur joylashgan komponentlarga olib kelishi mumkin (masalan, `withAuth(withRouter(withLogger(MyComponent)))`), bu esa disk raskadrovkani qiyinlashtiradi.
- Prop Nomlarining To'qnashuvi: Agar HOC o'ralgan komponent tomonidan allaqachon ishlatilayotgan propni (masalan, `data`) kiritsa, u tasodifan qayta yozilishi mumkin.
- Yashirin Mantiq: Komponent kodidan uning proplari qayerdan kelayotganini har doim ham aniq bilib bo'lmaydi. Mantiq HOC ichida yashiringan bo'ladi.
4-Usul: Render Proplar
Render Prop naqshi HOC'larning ba'zi kamchiliklariga yechim sifatida paydo bo'ldi. U mantiqni ulashishning yanada aniqroq usulini taklif etadi.
Render prop'ga ega bo'lgan komponent prop sifatida funksiya oladi (odatda `render` deb nomlanadi) va nima render qilishni aniqlash uchun ushbu funksiyani chaqiradi, unga har qanday holat (state) yoki mantiqni argument sifatida uzatadi.
Keling, sichqonchaning X va Y koordinatalarini kuzatib boradigan va ulardan foydalanmoqchi bo'lgan har qanday komponent uchun mavjud qiladigan `MouseTracker` komponentini yarataylik.
// MouseTracker.js - Render prop'li komponent
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);
};
}, []);
// Render funksiyasini holat (state) bilan chaqirish
return render(position);
}
// App.js - MouseTracker'dan foydalanish
function App() {
return (
<div>
<h1>Sichqonchangizni harakatlantiring!</h1>
<MouseTracker
render={mousePosition => (
<p>Joriy sichqoncha pozitsiyasi ({mousePosition.x}, {mousePosition.y})</p>
)}
/>
</div>
);
}
Bu yerda `MouseTracker` sichqoncha harakatini kuzatish uchun barcha mantiqni o'z ichiga oladi. U o'zi hech narsa render qilmaydi. Buning o'rniga, u render qilish mantiqini o'zining `render` propiga topshiradi. Bu HOC'larga qaraganda ancha aniqroq, chunki siz `mousePosition` ma'lumotlari qayerdan kelayotganini to'g'ridan-to'g'ri JSX ichida ko'rishingiz mumkin.
`children` propi ham funksiya sifatida ishlatilishi mumkin, bu ushbu naqshning keng tarqalgan va elegant variantidir:
// children'ni funksiya sifatida ishlatish
<MouseTracker>
{mousePosition => (
<p>Joriy sichqoncha pozitsiyasi ({mousePosition.x}, {mousePosition.y})</p>
)}
</MouseTracker>
5-Usul: Hooklar (Zamonaviy va Afzal Ko'rilgan Yondashuv)
React 16.8 versiyasida taqdim etilgan Hooklar React komponentlarini yozish usulimizni inqilob qildi. Ular sizga funksional komponentlarda holat (state) va boshqa React xususiyatlaridan foydalanish imkonini beradi. Eng muhimi, maxsus Hooklar komponentlar o'rtasida holatli mantiqni ulashish uchun eng elegant va to'g'ridan-to'g'ri yechimni taqdim etadi.
Hooklar HOC'lar va Render Proplar muammolarini ancha toza usulda hal qiladi. Keling, `MouseTracker` misolimizni `useMousePosition` deb nomlangan maxsus hookka aylantiramiz.
// hooks/useMousePosition.js - Maxsus Hook
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);
};
}, []); // Bo'sh bog'liqliklar massivi bu effekt faqat bir marta ishlashini anglatadi
return position;
}
// DisplayMousePosition.js - Hook'dan foydalanadigan komponent
import { useMousePosition } from './hooks/useMousePosition';
function DisplayMousePosition() {
const position = useMousePosition(); // Shunchaki hookni chaqiring!
return (
<p>
Sichqoncha pozitsiyasi ({position.x}, {position.y})
</p>
);
}
// Boshqa bir komponent, ehtimol interaktiv element
import { useMousePosition } from './hooks/useMousePosition';
function InteractiveBox() {
const { x, y } = useMousePosition();
const style = {
position: 'absolute',
top: y - 25, // Qutini kursor markaziga joylashtirish
left: x - 25,
width: '50px',
height: '50px',
backgroundColor: 'lightblue',
};
return <div style={style} />;
}
Bu juda katta yaxshilanishdir. 'Wrapper do'zaxi', prop nomlarining to'qnashuvi va murakkab render prop funksiyalari yo'q. Mantiq qayta ishlatiladigan funksiyaga (`useMousePosition`) to'liq ajratilgan va har qanday komponent ushbu holatli mantiqqa bitta, aniq kod satri bilan 'ulanib olishi' mumkin. Maxsus Hooklar zamonaviy React'da kompozitsiyaning eng yuqori ifodasidir, bu sizga o'zingizning qayta ishlatiladigan mantiq bloklari kutubxonangizni yaratish imkonini beradi.
Tezkor Taqqoslash: React'da Kompozitsiya va Vorislik
React kontekstidagi asosiy farqlarni umumlashtirish uchun, bu yerda to'g'ridan-to'g'ri taqqoslash keltirilgan:
Jihat | Vorislik (React'da Anti-Naqsh) | Kompozitsiya (React'da Afzal Ko'riladi) |
---|---|---|
Munosabat | 'is-a' munosabati. Ixtisoslashgan komponent asosiy komponentning bir versiyasi hisoblanadi. | 'has-a' yoki 'uses-a' munosabati. Murakkab komponent kichikroq komponentlarga ega yoki umumiy mantiqdan foydalanadi. |
Bog'liqlik | Yuqori. Quyi komponentlar ota-onasining implementatsiyasiga qattiq bog'langan. | Past. Komponentlar mustaqil va o'zgartirishsiz turli kontekstlarda qayta ishlatilishi mumkin. |
Moslashuvchanlik | Past. Qattiq, sinflarga asoslangan ierarxiyalar mantiqni turli komponentlar daraxtlari bo'ylab ulashishni qiyinlashtiradi. | Yuqori. Mantiq va UI qurilish bloklari kabi son-sanoqsiz usullarda birlashtirilishi va qayta ishlatilishi mumkin. |
Kodning Qayta Ishlatilishi | Oldindan belgilangan ierarxiya bilan cheklangan. Siz shunchaki "banan"ni xohlaganingizda butun "gorilla"ni olasiz. | A'lo. Kichik, maqsadli komponentlar va hooklar butun dastur bo'ylab ishlatilishi mumkin. |
React Idiomasi | Rasmiy React jamoasi tomonidan tavsiya etilmaydi. | React dasturlarini yaratish uchun tavsiya etilgan va idiomatik yondashuv. |
Xulosa: Kompozitsiya Bilan Fikrlang
Kompozitsiya va vorislik o'rtasidagi bahs dasturiy ta'minot dizaynidagi asosiy mavzudir. Vorislik klassik OYDda o'z o'rniga ega bo'lsa-da, UI ishlab chiqishning dinamik, komponentlarga asoslangan tabiati uni React uchun yomon tanlovga aylantiradi. Kutubxona asosan kompozitsiyani qabul qilish uchun ishlab chiqilgan.
Kompozitsiyani afzal ko'rish orqali siz quyidagilarga ega bo'lasiz:
- Moslashuvchanlik: Kerak bo'lganda UI va mantiqni aralashtirish va moslashtirish qobiliyati.
- Qo'llab-quvvatlanuvchanlik: Bog'liqligi past bo'lgan komponentlarni alohida tushunish, sinovdan o'tkazish va refaktor qilish osonroq.
- Masshtablanuvchanlik: Kompozitsion fikrlash katta, murakkab dasturlarni samarali yaratish uchun ishlatilishi mumkin bo'lgan kichik, qayta ishlatiladigan komponentlar va hooklar dizayn tizimini yaratishga undaydi.
Global React dasturchisi sifatida kompozitsiyani o'zlashtirish shunchaki eng yaxshi amaliyotlarga rioya qilish emas - bu React'ni shunday kuchli va samarali vositaga aylantirgan asosiy falsafani tushunishdir. Kichik, maqsadli komponentlar yaratishdan boshlang. Umumiy konteynerlar uchun `props.children` va ixtisoslashtirish uchun proplardan foydalaning. Mantiqni ulashish uchun birinchi navbatda maxsus Hooklarga murojaat qiling. Kompozitsiya bilan fikrlash orqali siz vaqt sinovidan o'tadigan elegant, mustahkam va masshtablanuvchan React dasturlarini yaratish yo'lida bo'lasiz.