Render Props pattern
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