Render Props pattern

~15 daq · React · Component Patterns

Muammodan boshlaylik

Sichqoncha qayerda turganini kuzatuvchi komponent yozyapsiz. Bir sahifada koordinatalar matn sifatida ko'rsatiladi. Boshqa sahifada esa sichqoncha pozitsiyasida kichik element harakatlanadi.

Mantiq bir xil — sichqonchani kuzatish. Ko'rinish boshqacha.

Birinchi fikr — ikki alohida komponent:

function KoordinatlarKo'rsatuvchi() {
  const [pozitsiya, setPozitsiya] = useState({ x: 0, y: 0 });
  // ... kuzatish kodi
  return <p>X: {pozitsiya.x}, Y: {pozitsiya.y}</p>;
}

function HarakatlanuvchiElement() {
  const [pozitsiya, setPozitsiya] = useState({ x: 0, y: 0 });
  // ... xuddi shu kuzatish kodi — takrorlandi!
  return <div style={{ left: pozitsiya.x, top: pozitsiya.y }}>🐱</div>;
}

Kuzatish kodi ikki joyda takrorlandi. Ertaga uni o'zgartirish kerak bo'lsa — ikki joyni o'zgartirish kerak.


Yechim: mantiqni ajratish

Mantiqni bir joyga chiqarib, ko'rinishni tashqaridan berish kerak. Lekin komponent odatda o'zi chizadi — tashqaridan "nima chizishni" qanday aytamiz?

Javob: funksiya props sifatida berish. Komponent "nima chizishni" bilmaydi — tashqaridan berilgan funksiyani chaqiradi, u qaytargan JSX ni ko'rsatadi.

Bu — Render Props pattern.

function SichqonchaKuzatuvchi({ render }) {
  const [pozitsiya, setPozitsiya] = useState({ x: 0, y: 0 });

  return (
    <div
      onMouseMove={e => setPozitsiya({ x: e.clientX, y: e.clientY })}
      style={{ height: '300px', border: '1px solid #ccc' }}
    >
      {render(pozitsiya)}  {/* funksiyani chaqiradi, natijani ko'rsatadi */}
    </div>
  );
}

Endi bir xil komponent — ikki xil ko'rinish:

// Koordinatalar matn sifatida
<SichqonchaKuzatuvchi
  render={({ x, y }) => <p>X: {x}, Y: {y}</p>}
/>

// Harakatlanuvchi element
<SichqonchaKuzatuvchi
  render={({ x, y }) => (
    <div style={{ position: 'absolute', left: x, top: y }}>🐱</div>
  )}
/>

Kuzatish kodi bir joyda. Ko'rinish tashqaridan beriladi. Ertaga uchinchi xil ko'rinish kerak bo'lsa — SichqonchaKuzatuvchi ga tegmaysiz.


children funksiya sifatida

Render Props ning yana bir shakli — render props o'rniga children ni funksiya sifatida berish. Ko'rinishi biroz boshqacha, lekin g'oya bir xil.

function DataYuklovchi({ url, children }) {
  const [data, setData] = useState(null);
  const [yuklanmoqda, setYuklanmoqda] = useState(true);

  useEffect(() => {
    fetch(url).then(r => r.json()).then(d => {
      setData(d);
      setYuklanmoqda(false);
    });
  }, [url]);

  return children({ data, yuklanmoqda });  // children — funksiya
}
<DataYuklovchi url="/api/users">
  {({ data, yuklanmoqda }) => {
    if (yuklanmoqda) return <p>Yuklanmoqda...</p>;
    return <ul>{data.map(u => <li key={u.id}>{u.ism}</li>)}</ul>;
  }}
</DataYuklovchi>

{/* Xuddi shu komponent — boshqa ko'rinish */}
<DataYuklovchi url="/api/users">
  {({ data, yuklanmoqda }) => {
    if (yuklanmoqda) return <div className="skeleton" />;
    return <UserGrid users={data} />;
  }}
</DataYuklovchi>

DataYuklovchi ma'lumot olishni biladi. Qanday ko'rsatishni bilmaydi — tashqaridan beriladi.


Hozir bu pattern qayerda uchraydi?

Hooks paydo bo'lishidan oldin (2019 yilgacha) Render Props juda keng ishlatilardi. Hozir custom hook ko'p hollarda yaxshiroq — soddaroq yoziladi.

Lekin Render Props hali ham kutubxonalarda uchraydi. Masalan, React Router:

<Route path="/profil" render={(props) => <Profil {...props} />} />

Yoki Formik, Downshift kabi kutubxonalar. Ularni ishlatayotganda bu pattern ni tushunmasangiz — kod nima qilayotganini bilmaysiz.


Custom Hook bilan solishtirish

// Render Props bilan
<SichqonchaKuzatuvchi
  render={({ x, y }) => <p>{x}, {y}</p>}
/>

// Custom Hook bilan — ancha sodda
function App() {
  const { x, y } = useSichqoncha();
  return <p>{x}, {y}</p>;
}

Custom hook — mantiqni qayta ishlatish uchun yaxshiroq. Render Props — komponent ichida mantiq va render ni birga boshqarish kerak bo'lganda.


Xulosa

Render Props — komponentga funksiya props sifatida berish. Komponent mantiqni boshqaradi, funksiya ko'rsatishni hal qiladi.

<Komponent render={(data) => <JSX />} />
           ↑
           bu funksiya — komponent chaqiradi, natijani ko'rsatadi

O'zingiz yozayotganda custom hook yaxshiroq. Lekin kutubxonalarda uchraydi — tushunish muhim.


Keyingi dars

33-dars: Compound Component pattern