IlmHamroh
JavaScript Full-stack/18-qism. React chuqur28/42-dars17 daqiqa
Mundarija (26)

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: withX nomlash, 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:

jsx
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):

jsx
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:

text
Buyurtma berish mumkin

vazifalar 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.

jsx
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:

text
withOnline(Cart)

Ekranda:

text
Jami: 40000 so'm — buyurtma berish mumkin

Uch narsaga qarang:

  1. withOnline(Cart) — chaqiruv komponent qaytaradi. CartWithOnline ni oddiy komponent kabi ishlatamiz.
  2. {...props} — HOC o'zi olgan props'ni (total={40000}) o'ralgan komponentga uzatadi va o'zinikini (online) qo'shadi. Uzatishni unutsangiz, Cart total ni ko'rmaydi.
  3. displayName — React DevTools'da komponent daraxtida ko'rinadigan nom. Busiz daraxtda WithOnline turadi — 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):

jsx
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:

jsx
export default connect(mapStateToProps)(
  withRouter(withTranslation()(OrderList)),
);

HOC'lar ichkaridan tashqariga o'qiladi — xuddi matematikadagi f(g(x)) kabi:

  1. withTranslation()(OrderList) — t funksiyasini qo'shadi (tarjima). withTranslation() avval sozlama oladi, keyin HOC qaytaradi. Shuning uchun ikki juft qavs.
  2. withRouter(…) — history, location, match ni qo'shadi.
  3. connect(mapStateToProps)(…) — Redux store'dan mapStateToProps qaytargan maydonlarni (masalan orders) 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)) va withB(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:

jsx
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:

text
mount
mount

Ekranda:

text
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:

jsx
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:

text
Ko'k choy × 2 = 10000 so'm

children 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":

jsx
<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):

tsx
      <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:

  1. HOC yoki render prop komponentining ichidagi state va effektlarni useX funksiyasiga ko'chiring. U ilgari props sifatida berilgan qiymatlarni qaytarsin.
  2. Iste'molchi komponentda hookni chaqiring va HOC'ni olib tashlang.
  3. Eski HOC'ni darhol o'chirmang — uni yangi hook ustiga qayta yozing. Shunda hali ko'chirilmagan joylar ishlayveradi:
jsx
// 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.

jsx
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:

text
Achchiq: ha
Yechim
jsx
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:

text
Achchiq: ha

State 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.

jsx
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:

text
Osh × 1 = NaN so'm +1 porsiya
Yangila
Yechim
jsx
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:

text
withLog(Dish)
withLog(Dish)

Ekranda:

text
Osh × 3 = 105000 so'm +1 porsiya
Yangila

Uch 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, withStyles bilan to'la. Ularni qo'llab-quvvatlash — ko'p junior ishining birinchi vazifasi.
  • Kutubxona API'si: memo, lazy, withErrorBoundary, Next.js'ning eski withRouter i — HOC. React Aria'ning className funksiyasi, 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 va displayName.
  • 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
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
HOC va render props React'da: eski naqshlarni o'qish va hooklarga almashtirish — IlmHamroh