Mundarija (26)
- Bu darsda
- 1. Nega bu kerak?
- 2. Muammo: bitta mantiq — ko'p komponent
- 2.1 Qisqa tarix
- 3. HOC — komponent yasaydigan funksiya
- 3.1 Tuzilishi
- 3.2 Class davridagi HOC
- 3.3 Siz allaqachon HOC ishlatgansiz
- 3.4 Zanjirni o'qish
- 4. HOC tuzoqlari
- 4.1 Props to'qnashuvi
- 4.2 Renderda HOC yasash
- 4.3 Boshqa tuzoqlar — qisqacha
- 5. Render props — "nima chizishni sen ayt"
- 5.1 Tuzilishi
- 5.2 Kamchiligi: zinapoya
- 5.3 Render props hali ham o'rinli joylar
- 6. Hookka ko'chirish
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): qaysi naqsh?
- 2-mashq (o'rta): render prop'dan hookka
- 3-mashq (qiyin): withLog ni tuzatish
- 9. Real ishda
- Xulosa
- Manbalar
HOC va render props React'da: eski naqshlarni o'qish va hooklarga almashtirish
Qisqacha: Hooklardan oldin (2019 gacha) React'da mantiqni ulashishning ikki yo'li bor edi. HOC (higher-order component) — komponentni olib, unga props qo'shadigan yangi komponent qaytaradigan funksiya:
withOnline(DishList). Render props — komponent nima chizishni sizdan funksiya sifatida so'raydi:<Online>{(online) => …}</Online>. Ikkalasining o'rnini endi custom hook egallagan, lekin legacy kodda, eski kutubxonalarda (connect,withRouter, Formik) va React'ning o'zida (memo,lazy— aslida HOC) ular har kuni uchraydi. Bu dars ularni o'qish, tuzoqlarini tanish va hookka ko'chirishni o'rgatadi.
Bu darsda
- HOC'ni o'qiysiz va yozasiz:
withXnomlash, props uzatish,displayName. - HOC tuzoqlarini taniysiz: props to'qnashuvi, "o'ramlar do'zaxi", renderda HOC yasash.
- Render props va "children as function" ni o'qiysiz va ular qayerda hali ham o'rinli ekanini bilasiz.
- Eski naqshni custom hookka ko'chirasiz.
connect(…)(withRouter(…))kabi zanjirni ichkaridan tashqariga o'qiysiz.
Oldin bilishingiz kerak: Custom hooklar I: mantiqni ajratib olish, Controlled va uncontrolled komponent API dizayni, Class komponentlarni o'qish.
1. Nega bu kerak?
Oldingi darsda state reducer naqshini ko'rdik. Uning ildizi — hooklardan oldingi davrda. Bu darsda o'sha davrga qaytamiz.
Sardor yangi ishga kirdi. Birinchi vazifa — 2019 yilda yozilgan buyurtmalar panelida kichik o'zgarish. U faylni ochib, shuni ko'rdi:
export default connect(mapStateToProps)(
withRouter(withTranslation()(OrderList)),
);useState yo'q, useEffect yo'q — lekin komponent orders, history, t props'larini qayerdandir oladi. Sardor qotib qoldi: bu props'lar qayerdan keladi?
Bu holat noyob emas. Katta kompaniyalardagi React kodining sezilarli qismi hooklardan oldin yozilgan va hali ham ishlab turibdi. Yangi kutubxonalar ham ba'zan render props ishlatadi — chunki ba'zi vazifalarda u hali ham eng qulay. Ularni yozish shart emas, lekin o'qiy olish shart.
Hayotiy o'xshatish: eski uyni ta'mirlayotgan usta. U bugun zamonaviy truba yotqizadi, lekin devor ichidagi eski temir trubalarni taniy olishi kerak. Ularni bilmasa, birinchi teshikda uyni suvga bostiradi.
2. Muammo: bitta mantiq — ko'p komponent
«Bahor» ilovasida uchta komponent internet bor-yo'qligini bilishi kerak: menyu (oflayn bo'lsa, "eski narxlar" deb yozadi), savat ("buyurtma yuborilmaydi") va sarlavha (qizil nuqta). Mantiq bir xil: navigator.onLine ni o'qish va online/offline hodisalariga obuna bo'lish.
Bugun buni custom hook hal qiladi (Custom hooklar I):
import { useEffect, useState } from "react";
function useOnline() {
const [online, setOnline] = useState(navigator.onLine);
useEffect(() => {
const on = () => setOnline(true);
const off = () => setOnline(false);
addEventListener("online", on);
addEventListener("offline", off);
return () => {
removeEventListener("online", on);
removeEventListener("offline", off);
};
}, []);
return online;
}
function Cart() {
const online = useOnline();
return <p>{online ? "Buyurtma berish mumkin" : "Internet yo'q"}</p>;
}
function App() {
return <Cart />;
}Ekranda:
Buyurtma berish mumkinvazifalar da bu hook allaqachon bor — useOnlayn (useSyncExternalStore bilan). Hooklar 2019 yilda (React 16.8) chiqdi. Undan oldin funksiya komponentda state yo'q edi, mantiq class komponentlarda yashardi (Class komponentlarni o'qish). Class'dan mantiqni "sug'urib olish" uchun ikki naqsh o'ylab topildi.
2.1 Qisqa tarix
React jamoasi mantiq ulashish muammosini to'rt marta yechdi. Har yechim oldingisining kamchiligidan tug'ildi:
| Yil | Usul | Nega keyingisiga o'tildi |
|---|---|---|
| 2013 | mixin (createClass ichida) |
mixinlar bir-birining metodlarini jim almashtirardi |
| 2015 | HOC | props to'qnashuvi, o'ramlar do'zaxi |
| 2017 | render props | zinapoya, har renderda yangi funksiya |
| 2019 | hooklar | — bugungi standart |
Mixinlarni deyarli uchratmaysiz — ular class sintaksisida ishlamaydi va 2016 yildayoq React blogida "zararli" deb e'lon qilingan. HOC va render props esa class'lar bilan ham, funksiyalar bilan ham ishlaydi, shuning uchun ular hali ko'p. Bu tarixni bilish kodning yoshini aniqlashga yordam beradi: withX va connect ko'rsangiz — fayl 2016–2019 davri yoki o'sha davr kutubxonasini ishlatadi.
3. HOC — komponent yasaydigan funksiya
3.1 Tuzilishi
HOC (higher-order component, yuqori tartibli komponent) — komponentni argument sifatida oladigan va yangi komponent qaytaradigan funksiya. Nom yuqori tartibli funksiya (HOF) dan olingan: map funksiyani oladi, HOC esa komponentni.
import { useEffect, useState } from "react";
function withOnline(Component) {
function WithOnline(props) {
const [online, setOnline] = useState(navigator.onLine);
useEffect(() => {
const on = () => setOnline(true);
const off = () => setOnline(false);
addEventListener("online", on);
addEventListener("offline", off);
return () => {
removeEventListener("online", on);
removeEventListener("offline", off);
};
}, []);
return <Component {...props} online={online} />;
}
WithOnline.displayName = `withOnline(${Component.name})`;
return WithOnline;
}
function Cart({ online, total }) {
return (
<p>
Jami: {total} so'm —{" "}
{online ? "buyurtma berish mumkin" : "internet yo'q"}
</p>
);
}
const CartWithOnline = withOnline(Cart);
function App() {
console.log(CartWithOnline.displayName);
return <CartWithOnline total={40000} />;
}Konsolda:
withOnline(Cart)Ekranda:
Jami: 40000 so'm — buyurtma berish mumkinUch narsaga qarang:
withOnline(Cart)— chaqiruv komponent qaytaradi.CartWithOnlineni oddiy komponent kabi ishlatamiz.{...props}— HOC o'zi olgan props'ni (total={40000}) o'ralgan komponentga uzatadi va o'zinikini (online) qo'shadi. Uzatishni unutsangiz,Carttotalni ko'rmaydi.displayName— React DevTools'da komponent daraxtida ko'rinadigan nom. Busiz daraxtdaWithOnlineturadi — qaysi komponentni o'ragani noma'lum. Odat:withX(Asl).
Cart endi ikki narsani bilmaydi: online qayerdan kelishini va qanday hisoblanishini. U uni oddiy props deb oladi. Mana HOC'ning g'oyasi — mantiq tashqarida, komponent "toza".
3.2 Class davridagi HOC
Legacy kodda HOC'ning ichi ko'pincha class bo'ladi. Mantiq o'sha, faqat hayot sikli metodlari bilan (Class komponentlarni o'qish):
function withOnline(Component) {
return class WithOnline extends React.Component {
state = { online: navigator.onLine };
on = () => this.setState({ online: true });
off = () => this.setState({ online: false });
componentDidMount() {
addEventListener("online", this.on);
addEventListener("offline", this.off);
}
componentWillUnmount() {
removeEventListener("online", this.on);
removeEventListener("offline", this.off);
}
render() {
return <Component {...this.props} online={this.state.online} />;
}
};
}O'qishda uchta joyni toping va qolganini o'tkazib yuboring. state — HOC nimani saqlaydi. componentDidMount/componentWillUnmount — qachon obuna bo'ladi va qachon tozalaydi (hookdagi effekt va cleanup). render — o'ralgan komponentga nima qo'shiladi (online). Bu uchtasi topilsa, HOC'ning butun vazifasi ma'lum.
3.3 Siz allaqachon HOC ishlatgansiz
React'ning o'zida HOC'lar bor. Ular komponentni olib, yangi "maxsus" komponent qaytaradi:
| API | Nima qaytaradi | Darsi |
|---|---|---|
memo(Component) |
props o'zgarmasa, qayta chizilmaydigan komponent | memo |
lazy(() => import(…)) |
kodi keyin yuklanadigan komponent | lazy |
forwardRef(Component) |
ref oladigan komponent (React 19 da shart emas) | useRef II |
Bular nomida with yo'q, lekin naqsh o'sha: kirishda nimadir, chiqishda yangi komponent. (lazy komponentning o'zini emas, uni yuklaydigan funksiyani oladi — shuning uchun u HOC'ga yaqin qarindosh.) Kutubxonalarda: connect (react-redux), withRouter (React Router 5), withTranslation (react-i18next), withStyles (MUI 4), withErrorBoundary (react-error-boundary).
3.4 Zanjirni o'qish
Sardorning faylidagi qatorga qaytamiz:
export default connect(mapStateToProps)(
withRouter(withTranslation()(OrderList)),
);HOC'lar ichkaridan tashqariga o'qiladi — xuddi matematikadagi f(g(x)) kabi:
withTranslation()(OrderList)—tfunksiyasini qo'shadi (tarjima).withTranslation()avval sozlama oladi, keyin HOC qaytaradi. Shuning uchun ikki juft qavs.withRouter(…)—history,location,matchni qo'shadi.connect(mapStateToProps)(…)— Redux store'danmapStateToPropsqaytargan maydonlarni (masalanorders) qo'shadi.
Natijada OrderList to'rt manbadan props oladi: o'z otasidan va uchta HOC'dan. DevTools'da daraxt shunday ko'rinadi:
flowchart TD
A["Connect(withRouter(…))"] --> B["withRouter(withTranslation(OrderList))"]
B --> C["withTranslation(OrderList)"]
C --> D["OrderList<br/>props: orders, history, t, ..."]
H["useSelector · useNavigate ·<br/>useTranslation"] -.->|hooklar bilan| D2["OrderList<br/>bitta tugun"]Diagrammaning chap qismi — "o'ramlar do'zaxi" (wrapper hell): bitta komponent uchun to'rt qavat. O'ng tomonda o'sha mantiq hooklar bilan: daraxtda faqat OrderList. Bugungi kutubxonalarning hammasi hook beradi: useSelector, useNavigate, useTranslation.
Tekshirib ko'ring:
withA(withB(Card))vawithB(withA(Card))— har doim bir xilmi?
Javob
Har doim emas. Ikkalasi ham bir xil nomli props qo'shsa, ichki HOC'niki (ya'ni Card ga yaqinroq) oxirgi bo'lib yoziladi va yutadi. Bundan tashqari, tashqi HOC ichkisi qo'shgan props'ni ko'rmaydi, ichkisi esa tashqisinikini ko'radi. Tartib — ma'no. Shuning uchun eski kodda HOC'lar tartibini "chiroyli" qilish uchun almashtirmang.
4. HOC tuzoqlari
4.1 Props to'qnashuvi
Ikki HOC bir xil nomli props qo'shsa, biri ikkinchisini jim yopib qo'yadi. withOnline online qo'shadi. Boshqa jamoaning withStatus HOC'i ham online qo'shadi — lekin u "oshxona ochiqmi" ma'nosida. withStatus(withOnline(Menu)) da Menu faqat bittasini ko'radi, xato esa yo'q. Hooklarda bu muammo yo'q: const internet = useOnline(); const open = useStatus(); — nomni siz tanlaysiz.
4.2 Renderda HOC yasash
Eng xavfli xato — HOC'ni komponent ichida chaqirish:
import { useEffect, useState } from "react";
function withLog(Component) {
function WithLog(props) {
useEffect(() => console.log("mount"), []);
return <Component {...props} />;
}
return WithLog;
}
function Portion() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>Porsiya: {n}</button>;
}
function App() {
const [tick, setTick] = useState(0);
const LoggedPortion = withLog(Portion); // ❌ har renderda yangi
return (
<div>
<LoggedPortion />
<p>
<button onClick={() => setTick(tick + 1)}>Ota: {tick}</button>
</p>
</div>
);
}Konsolda:
mount
mountEkranda:
Porsiya: 0
Ota: 1| Qadam | Ekranda | Konsolda |
|---|---|---|
| birinchi chizish | Porsiya: 0, Ota: 0 |
mount |
| «Porsiya» × 2 | Porsiya: 2 |
— |
| «Ota» | Porsiya: 0, Ota: 1 |
mount (yangi komponent) |
Porsiya ikki marta bosildi — 2 bo'ldi. Keyin ota qayta chizildi va porsiya 0 ga qaytdi, konsolda ikkinchi mount. Sabab: har App renderida withLog(Portion) yangi funksiya — yangi komponent turini — qaytaradi. React tur o'zgarganini ko'radi va eskisini o'chirib, yangisini noldan yaratadi (State'ning saqlanishi). Ichidagi state, fokus, input matni — hammasi yo'qoladi.
Davosi — HOC'ni modul darajasida, komponentdan tashqarida bir marta chaqirish: const LoggedPortion = withLog(Portion); faylning yuqorisida. lazy uchun ham xuddi shu qoida: vazifalar da lazy() modul darajasida chaqirilgan va izohda aynan shu sabab yozilgan (lazy).
4.3 Boshqa tuzoqlar — qisqacha
| Tuzoq | Belgisi | Eski davosi |
|---|---|---|
| Statik xususiyatlar yo'qoladi | Card.Header (compound) o'ralgandan keyin undefined |
hoist-non-react-statics paketi |
ref o'ralgan komponentga yetmaydi |
ref.current — o'ram yoki null |
forwardRef |
| Props qayerdan kelgani noma'lum | o'qiganda chalkashlik | hujjat, TypeScript |
React 19 da ikkinchi qator o'zgardi: ref endi oddiy props (useRef II). {...props} uni ham uzatadi — HOC'da forwardRef kerak emas. Lekin eski kodda forwardRef ko'p uchraydi. Ikkalasini ham taniyotganingizni bilib qo'ying.
Uchinchi qatorga TypeScript ham yordam beradi, lekin HOC'ni to'g'ri tiplash qiyin. Funksiya "P props'li komponentni ol, P dan online ni olib tashlangan props'li komponent qaytar" degan generic tur yozishi kerak. Kutubxonalardagi HOC turlari shuning uchun o'nlab qatorli bo'ladi. Hookning turi esa oddiy: function useOnline(): boolean. Bu ham hooklar g'olib chiqishining sabablaridan biri (React + TS IV da generic komponentlar).
5. Render props — "nima chizishni sen ayt"
5.1 Tuzilishi
Render props — komponent nimani chizishni o'zi hal qilmaydi: u sizdan funksiya oladi va unga o'z ma'lumotini berib chaqiradi. Funksiya JSX qaytaradi:
import { useState } from "react";
function Counter({ children }) {
const [count, setCount] = useState(0);
return children(count, () => setCount(count + 1));
}
function App() {
return (
<Counter>
{(count, increment) => (
<p>
<button onClick={increment}>Ko'k choy</button> × {count}
{" "}= {count * 5000} so'm
</p>
)}
</Counter>
);
}Ekranda:
Ko'k choy × 2 = 10000 so'mchildren bu yerda JSX emas, funksiya — "children as function" (bola sifatida funksiya). Counter state'ni saqlaydi va uni funksiyaga beradi. Ko'rinish to'liq chaqiruvchida: tugma, matn, hisob. Xuddi shuni render nomli props bilan ham yozish mumkin: <Counter render={(count, inc) => …} /> — naqsh nomi shundan.
HOC'dan farqi: props'lar "sehrli" paydo bo'lmaydi. count va increment — sizning funksiyangiz argumentlari, nomini o'zingiz tanlaysiz. To'qnashuv yo'q.
5.2 Kamchiligi: zinapoya
Bir nechta render prop birga kerak bo'lsa, kod o'ngga "qochadi":
<Online>
{(online) => (
<Theme>
{(theme) => (
<Cart>
{(items) => (
<CartView online={online} theme={theme} items={items} />
)}
</Cart>
)}
</Theme>
)}
</Online>Hooklar bilan — uch qator: const online = useOnline(); const theme = useTheme(); const items = useCart();. Ikkinchi kamchilik: ichki funksiya har renderda yangi, shuning uchun memo qilingan bolaga uzatilsa, memo foydasiz bo'ladi (memo).
5.3 Render props hali ham o'rinli joylar
Render props o'lmadi. U bir vazifada hookdan qulayroq: komponent sizdan qanday chizishni so'raganda — ayniqsa har element uchun yoki maxsus holatda. Siz bu naqshni allaqachon vazifalar da ko'rgansiz. XatoChegarasi ning fallback props'i — funksiya (Error boundary):
<XatoChegarasi
tiklashKaliti={kechikkan}
fallback={(_xato, qaytaUrin) => (
<p id="batafsil-xato" role="alert">
Statistikani yuklab yoki hisoblab bo'lmadi.{" "}
…
</p>
)}
>Chegara xato va "qayta urinish" funksiyasini beradi, nimani ko'rsatishni esa chaqiruvchi hal qiladi. Error boundary class komponent — unda hook yo'q, shuning uchun bu yerda render prop eng tabiiy yo'l. Boshqa zamonaviy misollar:
| Joy | Render prop |
|---|---|
| Virtual ro'yxatlar (react-window) | har qatorni chizish funksiyasi |
| React Aria Components | className={({ isFocused }) => …} — holatga qarab |
| Formik, React Final Form | <Formik>{(form) => …}</Formik> |
| Downshift | <Downshift>{(downshift) => …}</Downshift> (hook varianti ham bor) |
Tekshirib ko'ring:
function Counter({ children }) { … return children(count, inc); }—<Counter><p>Salom</p></Counter>deb ishlatilsa, nima bo'ladi?
Javob
Xato: children is not a function. children endi funksiya emas, JSX elementi (obyekt), uni chaqirib bo'lmaydi. Render prop komponenti children turini kutadi — eski kutubxonalar buni propTypes bilan, bugun esa TypeScript bilan (children: (count: number) => ReactNode) himoyalaydi.
6. Hookka ko'chirish
Eski kodni yangilashda qoida oddiy: mantiq — hookka, ko'rinish — komponentga. Retsept:
- HOC yoki render prop komponentining ichidagi state va effektlarni
useXfunksiyasiga ko'chiring. U ilgari props sifatida berilgan qiymatlarni qaytarsin. - Iste'molchi komponentda hookni chaqiring va HOC'ni olib tashlang.
- Eski HOC'ni darhol o'chirmang — uni yangi hook ustiga qayta yozing. Shunda hali ko'chirilmagan joylar ishlayveradi:
// Eski API'ni saqlash: HOC endi hookning yupqa o'rami
function withOnline(Component) {
function WithOnline(props) {
const online = useOnline();
return <Component {...props} online={online} />;
}
WithOnline.displayName = `withOnline(${Component.name})`;
return WithOnline;
}Bu bosqichma-bosqich ko'chirish (incremental migration): har PR'da bir nechta komponent, oxirida HOC ishlatilmay qoladi va o'chiriladi. knip kabi vositalar ishlatilmagan eksportni topib beradi. Bizning loyihada ham u bor: Dizayn tizimi darsidan boshlab har tekshiruvda ishga tushadi.
| Eski | Yangi | Misol |
|---|---|---|
withX(Component) |
const x = useX() |
withRouter → useNavigate, useLocation |
<X>{(x) => …}</X> |
const x = useX() |
<Query> → useQuery |
connect(mapState)(C) |
useSelector(selector) |
react-redux 7.1 dan |
forwardRef(C) |
ref — oddiy props |
React 19 |
Qachon ko'chirMASlik kerak: ishlab turgan, kam o'zgaradigan kod — faqat "eski" bo'lgani uchun qayta yozilmaydi. Har o'zgartirish xato xavfi. Ko'chirish o'sha faylga baribir tegayotganingizda yaxshi.
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| State har ota renderida nolga qaytadi | HOC komponent ichida chaqirilgan | modul darajasida bir marta |
| O'ralgan komponent o'z props'ini olmaydi | HOC {...props} ni uzatmadi |
<Component {...props} … /> |
DevTools'da Anonymous yoki WithX |
displayName yo'q |
`withX(${C.name})` |
children is not a function |
render prop komponentiga JSX berildi | funksiya bering |
| Props jim almashib qoldi | ikki HOC bir xil nom qo'shdi | hookka o'ting yoki nomini o'zgartiring |
| Eski kodni ko'chirgach test sindi | HOC tartibi ma'no edi | tartibni saqlang, bosqichma-bosqich |
8. Mashqlar
Mashqlar kurs/mashqlar/18/28-hoc-render-props/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): qaysi naqsh?
HOC, render prop yoki hook deb yozing:
export default memo(DishCard);:<Downshift>{(ds) => <input {...ds.getInputProps()} />}</Downshift>:const t = useTranslation();:export default withRouter(OrderPage);:
Yechim
memo — komponentni olib yangi komponent qaytaradi, demak HOC (nomida with bo'lmasa ham). Downshift'ning children i — funksiya: render prop. useTranslation — hook. withRouter — klassik withX HOC, bugun uning o'rnida useNavigate va useLocation.
2-mashq (o'rta): render prop'dan hookka
Quyidagi Toggle render prop bilan yozilgan. Uni useToggle hookiga ko'chiring: hook [on, toggle] qaytarsin, App render prop'siz yozilsin. Ekrandagi natija o'zgarmasin.
import { useState } from "react";
function Toggle({ children }) {
const [on, setOn] = useState(false);
return children(on, () => setOn(!on));
}
function App() {
return (
<Toggle>
{(on, toggle) => (
<button onClick={toggle}>
Achchiq: {on ? "ha" : "yo'q"}
</button>
)}
</Toggle>
);
}Ekranda:
Achchiq: haYechim
import { useState } from "react";
function useToggle(initial = false) {
const [on, setOn] = useState(initial);
return [on, () => setOn(!on)];
}
function App() {
const [on, toggle] = useToggle();
return (
<button onClick={toggle}>Achchiq: {on ? "ha" : "yo'q"}</button>
);
}Ekranda:
Achchiq: haState va uni o'zgartirish — hookda, tugma — App da. Bitta qavat kam, nomlar (on, toggle) chaqiruvchida. Hook kortej ([on, toggle]) qaytaradi — useState kabi, nomni har kim o'zi tanlashi uchun (Custom hooklar I — qaytarish shakli).
3-mashq (qiyin): withLog ni tuzatish
Sardor withLog HOC'ini yozdi. Uchta xato bor: (1) DevTools'da nom WithLog, (2) o'ralgan komponent price ni olmaydi, (3) ota qayta chizilganda Dish ning holati yo'qoladi. Hammasini tuzating. App boshida displayName konsolga chiqadi; +1 porsiya ikki marta va Yangila bir marta bosilgandan keyin porsiya 3 bo'lishi va narx ko'rinishi kerak.
Ishora: «Renderda HOC yasash» bo'limi va «Tuzilishi» dagi uch narsa.
import { useState } from "react";
function withLog(Component) {
function WithLog() {
return <Component />;
}
return WithLog;
}
function Dish({ price }) {
const [n, setN] = useState(1);
return (
<p>
Osh × {n} = {n * price} so'm{" "}
<button onClick={() => setN(n + 1)}>+1 porsiya</button>
</p>
);
}
function App() {
const [tick, setTick] = useState(0);
const LoggedDish = withLog(Dish);
console.log(LoggedDish.displayName);
return (
<div>
<LoggedDish price={35000} />
<button onClick={() => setTick(tick + 1)}>Yangila</button>
</div>
);
}Ekranda:
Osh × 1 = NaN so'm +1 porsiya
YangilaYechim
import { useState } from "react";
function withLog(Component) {
function WithLog(props) {
return <Component {...props} />; // ✅ props uzatiladi
}
WithLog.displayName = `withLog(${Component.name})`; // ✅ nom
return WithLog;
}
function Dish({ price }) {
const [n, setN] = useState(1);
return (
<p>
Osh × {n} = {n * price} so'm{" "}
<button onClick={() => setN(n + 1)}>+1 porsiya</button>
</p>
);
}
const LoggedDish = withLog(Dish); // ✅ modul darajasida — bir marta
function App() {
const [tick, setTick] = useState(0);
console.log(LoggedDish.displayName);
return (
<div>
<LoggedDish price={35000} />
<button onClick={() => setTick(tick + 1)}>Yangila</button>
</div>
);
}Konsolda:
withLog(Dish)
withLog(Dish)Ekranda:
Osh × 3 = 105000 so'm +1 porsiya
YangilaUch tuzatish uch xatoga mos. {...props} — price endi yetib boradi, NaN yo'qoldi. displayName — konsolda va DevTools'da withLog(Dish). LoggedDish modul darajasida — tur o'zgarmaydi, «Yangila» dan keyin ham porsiya 3. Konsolda ikki qator — App faqat ikki marta chizildi: boshida va «Yangila» da. +1 porsiya faqat Dish ning state'ini o'zgartiradi, shuning uchun faqat Dish qayta chiziladi, App emas (Qayta render sabablari). Xatoli variantda esa aynan «Yangila» LoggedDish ning turini almashtirgan va porsiyani 1 ga qaytargan edi.
9. Real ishda
- Legacy loyihalar: 2016–2019 yillarda yozilgan React ilovalari — banklar, ichki CRM'lar, eski SaaS'lar —
connect,withRouter,withStylesbilan to'la. Ularni qo'llab-quvvatlash — ko'p junior ishining birinchi vazifasi. - Kutubxona API'si:
memo,lazy,withErrorBoundary, Next.js'ning eskiwithRouteri — HOC. React Aria'ningclassNamefunksiyasi, react-window — render props. - Kod ko'rigi: "Bu HOC'ni hookka almashtirsa bo'ladimi?" — PR'larda tez-tez yoziladigan izoh. Renderda chaqirilgan HOC — ko'rikda topiladigan jiddiy xato.
- Intervyu savollari: "HOC va custom hook farqi?", "Render props nima va nega uning o'rnini hooklar oldi?", "Nega HOC'ni render ichida yasab bo'lmaydi?", "
memo— HOC'mi?".
Xulosa
- HOC — komponentni olib, unga props qo'shadigan yangi komponent qaytaradigan funksiya; odat —
withX,{...props}uzatish vadisplayName. - HOC zanjiri ichkaridan tashqariga o'qiladi; tartib ma'noga ega, props to'qnashuvi jim bo'ladi.
- HOC'ni hech qachon render ichida chaqirmang — har renderda yangi tur, state yo'qoladi.
- Render props — "nima chizishni funksiya bilan ayt"; zinapoya bo'lib ketadi, lekin chizish usulini so'raydigan joylarda (
fallback, virtual ro'yxat qatori) hali ham o'rinli. - Ko'chirish retsepti: mantiq — hookka, eski HOC — hook ustidagi yupqa o'ram, bosqichma-bosqich.
Keyingi dars: Polymorphic komponentlar va asChild — bitta komponent <button>, <a> yoki boshqa komponent sifatida chizilishi.
Manbalar
- React (eski hujjat): "Higher-Order Components" — legacy.reactjs.org/docs/higher-order-components.html
- React (eski hujjat): "Render Props" — legacy.reactjs.org/docs/render-props.html
- React: "Reusing Logic with Custom Hooks" — react.dev/learn/reusing-logic-with-custom-hooks
- React: "Legacy React APIs" — react.dev/reference/react/legacy
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!