useContext — global state, prop drilling muammosini hal qilish

~20 daq · React · Hooks — Ilg'or

Global state nima?

Ba'zi ma'lumotlar butun ilova bo'ylab kerak bo'ladi. Masalan:

  • Foydalanuvchi — kim login qilgan, ismi, roli
  • Tema — qorang'i yoki yorug'
  • Til — o'zbek, rus, ingliz
  • Savat — nechta mahsulot qo'shilgan

Bu ma'lumotlarni har bir komponentga props orqali uzatish — prop drilling. Oldingi darsda Context ni o'rgandik. Endi uni real loyihada qanday ishlatishni ko'ramiz.


Savat — amaliy misol

E-commerce saytda savat — klassik global state misoli. Mahsulot sahifasida "Savatga qo'shish" tugmasi bor. Navbar da savatdagi mahsulotlar soni ko'rsatiladi. Savat sahifasida ro'yxat ko'rsatiladi.

Bu uchta komponent bir-biridan uzoqda. Props bilan bog'lash — prop drilling. Context bilan — har biri to'g'ridan-to'g'ri oladi.

// SavatContext.jsx
import { createContext, useContext, useState } from 'react';

const SavatContext = createContext();

export function SavatProvider({ children }) {
  const [mahsulotlar, setMahsulotlar] = useState([]);

  // Savatga qo'shish — agar allaqachon bor bo'lsa, sonini oshir
  function qoshish(mahsulot) {
    setMahsulotlar(prev => {
      const bor = prev.find(m => m.id === mahsulot.id);
      if (bor) {
        return prev.map(m =>
          m.id === mahsulot.id ? { ...m, son: m.son + 1 } : m
        );
      }
      return [...prev, { ...mahsulot, son: 1 }];
    });
  }

  function ochirish(id) {
    setMahsulotlar(prev => prev.filter(m => m.id !== id));
  }

  // Jami narx — har render da hisoblanadi
  const jami = mahsulotlar.reduce((sum, m) => sum + m.narx * m.son, 0);

  return (
    <SavatContext.Provider value={{ mahsulotlar, qoshish, ochirish, jami }}>
      {children}
    </SavatContext.Provider>
  );
}

export function useSavat() {
  const context = useContext(SavatContext);
  if (!context) throw new Error('useSavat SavatProvider ichida ishlatilishi kerak');
  return context;
}

Endi istalgan komponentda useSavat() chaqiriladi — props shart emas:

// Navbar.jsx — savatdagi mahsulotlar sonini ko'rsatish
function Navbar() {
  const { mahsulotlar } = useSavat();

  return (
    <nav>
      <span>Do'kon</span>
      <span>🛒 {mahsulotlar.length}</span>
    </nav>
  );
}
// MahsulotKarta.jsx — savatga qo'shish
function MahsulotKarta({ mahsulot }) {
  const { qoshish } = useSavat();

  return (
    <div>
      <h3>{mahsulot.nomi}</h3>
      <p>{mahsulot.narx.toLocaleString()} so'm</p>
      <button onClick={() => qoshish(mahsulot)}>
        Savatga qo'shish
      </button>
    </div>
  );
}
// SavatSahifa.jsx — ro'yxat va jami
function SavatSahifa() {
  const { mahsulotlar, ochirish, jami } = useSavat();

  if (mahsulotlar.length === 0) return <p>Savat bo'sh</p>;

  return (
    <div>
      {mahsulotlar.map(m => (
        <div key={m.id}>
          <span>{m.nomi} × {m.son}</span>
          <button onClick={() => ochirish(m.id)}>O'chirish</button>
        </div>
      ))}
      <strong>Jami: {jami.toLocaleString()} so'm</strong>
    </div>
  );
}

MahsulotKarta da "Savatga qo'shish" bosilganda — Navbar dagi son avtomatik yangilanadi. Ular bir-birini bilmaydi, lekin bir xil Context dan foydalanadi.


Bir nechta Provider

Real loyihada bir nechta Context bo'ladi. Ularni App da ketma-ket o'rasiz:

function App() {
  return (
    <TemaProvider>
      <UserProvider>
        <SavatProvider>
          <Sahifalar />
        </SavatProvider>
      </UserProvider>
    </TemaProvider>
  );
}
TemaProvider
└── UserProvider
    └── SavatProvider
        └── istalgan komponent
            useTema()   → tema
            useUser()   → foydalanuvchi
            useSavat()  → savat

Har bir komponent faqat kerakli narsani oladi. useTema() chaqirgan komponent faqat tema o'zgarganda qayta chiziladi — savat o'zgarganda emas.


Context vs Zustand

Context — React ning o'z vositasi, qo'shimcha kutubxona kerak emas. Lekin cheklovi bor:

Context:
  ✅ Oddiy, o'rnatish shart emas
  ✅ Kichik-o'rta loyiha uchun yetarli
  ❌ Tez-tez o'zgaradigan ma'lumot uchun sekin
     (har o'zgarishda barcha consumer qayta chiziladi)

Zustand:
  ✅ Tez-tez o'zgaradigan ma'lumot uchun optimallashtirilgan
  ✅ Kichik va sodda API
  ❌ Qo'shimcha kutubxona

Foydalanuvchi ma'lumoti, tema, til — sekin o'zgaradi, Context yetarli. Real-time yangilanadigan katta state — Zustand yaxshiroq.


Xulosa

Context — global state uchun. Bir marta Provider bilan o'rasiz, istalgan joyda custom hook bilan olasiz.

Har bir Context uchun:

  • Alohida fayl
  • Provider komponenti
  • useXxx() custom hook — qulay interfeys va xato tekshiruvi

Keyingi dars

19-dars: useReducer — nima, useState dan farqi, qachon ishlatiladi