Higher Order Component — HOC nima, qachon kerak
Muammodan boshlaylik
Loyihada bir nechta sahifa bor — Profil, Sozlamalar, Admin panel. Bularni faqat login qilgan foydalanuvchilar ko'rishi kerak. Login qilmagan bo'lsa — login sahifasiga yo'naltirish kerak.
Birinchi fikr — har bir sahifaga tekshiruv qo'shish:
function ProfilSahifa() {
const { user } = useUser();
if (!user) return <Navigate to="/login" />;
return <div>Profil sahifasi</div>;
}
function SozlamalarSahifa() {
const { user } = useUser();
if (!user) return <Navigate to="/login" />; // xuddi shu 2 qator
return <div>Sozlamalar sahifasi</div>;
}
function AdminSahifa() {
const { user } = useUser();
if (!user) return <Navigate to="/login" />; // yana xuddi shu 2 qator
return <div>Admin panel</div>;
}
Ishlaydi. Lekin bir xil 2 qator har sahifada takrorlanmoqda. Ertaga tekshiruv mantig'i o'zgarganda — barcha sahifalarni topib o'zgartirish kerak. Sahifalar ko'paysa — muammo kuchayadi.
HOC nima?
Higher Order Component — komponent qabul qilib, yangi komponent qaytaradigan funksiya.
Bu g'oya JavaScript dagi Higher Order Function ga o'xshash. Array.map funksiya qabul qilib, yangi massiv qaytaradi. HOC esa komponent qabul qilib, yangi komponent qaytaradi.
withAuth(ProfilSahifa)
↑ ↑
funksiya kiruvchi komponent
↓
yangi komponent — tekshiruv + ProfilSahifa
withAuth HOC
import { Navigate } from 'react-router-dom';
import { useUser } from '../contexts/UserContext';
function withAuth(Komponent) {
// Yangi komponent — tekshiruv + asl komponent
function HimoyalananKomponent(props) {
const { user } = useUser();
if (!user) {
return <Navigate to="/login" />;
}
// Login qilgan — asl komponentni ko'rsatamiz
// props ni to'liq uzatamiz, hech narsa yo'qolmasin
return <Komponent {...props} />;
}
// React DevTools da "withAuth(ProfilSahifa)" ko'rinadi
HimoyalananKomponent.displayName = `withAuth(${Komponent.name})`;
return HimoyalananKomponent;
}
Endi har bir sahifaga tekshiruv yozish shart emas:
function ProfilSahifa() {
return <div>Profil sahifasi</div>; // tekshiruv yo'q
}
function SozlamalarSahifa() {
return <div>Sozlamalar sahifasi</div>; // tekshiruv yo'q
}
// HOC bilan o'rash — bir qator
export default withAuth(ProfilSahifa);
export default withAuth(SozlamalarSahifa);
export default withAuth(AdminSahifa);
Tekshiruv mantig'i o'zgarganda — faqat withAuth ni o'zgartirish yetarli. Barcha sahifalar avtomatik yangilanadi.
HOC vs Custom Hook
Hooks paydo bo'lishidan keyin (2019) ko'p HOC lar custom hook bilan almashtirildi. Lekin HOC ning o'z joyi bor.
Custom Hook:
mantiqni qayta ishlatadi
lekin render ni boshqara olmaydi
HOC:
mantiqni ham, render ni ham boshqaradi
komponentni to'liq o'rab oladi
withAuth misoli — login qilmagan bo'lsa <Navigate> qaytaradi. Bu render ni boshqarish. Custom hook bilan buni har komponentda yozish kerak bo'lardi:
// Custom hook bilan — har sahifada yozish kerak
function ProfilSahifa() {
const { user } = useUser();
if (!user) return <Navigate to="/login" />; // takrorlanadi
return <div>...</div>;
}
// HOC bilan — bir marta yoziladi
export default withAuth(ProfilSahifa);
Qayerda uchraydi?
HOC hozir ham keng ishlatiladi — asosan kutubxonalarda:
// React Redux
export default connect(mapStateToProps)(MyComponent);
// React Router (eski versiya)
export default withRouter(MyComponent);
// Material UI
export default withStyles(styles)(MyComponent);
Ularni ishlatayotganda bu pattern ni tushunmasangiz — nima uchun bunday yozilganini bilmaysiz.
Xulosa
HOC — komponent qabul qilib, yangi komponent qaytaradi. Bir xil mantiqni ko'p komponentga qo'shish uchun.
function withXxx(Komponent) {
function YangiKomponent(props) {
// qo'shimcha mantiq — render ni boshqarish mumkin
return <Komponent {...props} />;
}
return YangiKomponent;
}
Custom hook — mantiqni qayta ishlatish. HOC — render ni ham boshqarish kerak bo'lganda (auth redirect, loading screen, error boundary).
Keyingi dars
32-dars: Render Props pattern