React'te Bağımlı Filtreler: Bir Filtreyi Seçince Diğerinin Güncellenmesi

Ana Grup seçildiğinde Alt Grup listesinin otomatik güncellenmesi nasıl yapılır? React ile cascading (bağımlı) filtre pattern'ini adım adım uygulayın.

Sorun: Filtreler Birbiriyle Uyumsuz

Stok tablosunda 3 filtre var: Ana Grup, Alt Grup ve Depo. Kullanıcı “Seramik” ana grubunu seçiyor — ama Alt Grup menüsünde hâlâ boya, kablo, vida gibi alakasız seçenekler görünüyor.

Ana Grup: [Seramik ▼]    ← Seçildi
Alt Grup: [Tümü ▼]
           ├── Boya         ← Seramikle ne alakası var?
           ├── Kablo        ← İlgisiz
           ├── Yer Seramiği ← ✅ Bu olmalı
           └── Duvar Fayansı← ✅ Bu olmalı

Kullanıcı yanlış seçim yapıyor, sonuç bulamıyor, “sistem çalışmıyor” diyor.

Bağımlı filtre demek: Birinci filtreyi seçince, ikinci filtredeki seçenekler otomatik olarak ayıklansın.

Basit Mantık

1. Kullanıcı "Seramik" seçti
2. → Alt Grup listesi güncellenir: sadece Yer Seramiği, Duvar Fayansı, Mozaik
3. → Tablo da güncellenir: sadece seramik ürünleri gösterir

Adım 1: Filtre Durumunu Tutma

En önemli kısım: Ana Grup değişince Alt Grup sıfırlanmalı. Yoksa kullanıcı “Seramik → Boya” gibi imkansız bir kombinasyonda kalır.

function useFiltreler() {
  const [anaGrup, setAnaGrup] = useState('');
  const [altGrup, setAltGrup] = useState('');

  // Ana Grup değişince Alt Grup sıfırla
  const anaGrupDegistir = (yeniDeger) => {
    setAnaGrup(yeniDeger);
    setAltGrup('');  // ← Kritik: sıfırla
  };

  return {
    anaGrup, altGrup,
    anaGrupDegistir,
    setAltGrup,
  };
}

Adım 2: Alt Grup Seçeneklerini Ana Gruba Göre Çekme

Ana Grup seçildiğinde veritabanından sadece o grubun alt gruplarını getiriyoruz:

function useAltGrupSecenekleri(anaGrup) {
  return useQuery({
    queryKey: ['alt-gruplar', anaGrup],  // anaGrup değişince yeniden çeker
    queryFn: async () => {
      let sorgu = supabase
        .from('v3_stock')
        .select('alt_grup');

      // Ana Grup seçildiyse, sadece ona ait olanları getir
      if (anaGrup) {
        sorgu = sorgu.eq('ana_grup', anaGrup);
      }

      const { data } = await sorgu;
      // Tekrarsız liste oluştur
      return [...new Set(data?.map(d => d.alt_grup))];
    },
  });
}

Buradaki sihir: queryKey içinde anaGrup var. React Query, ana grup her değiştiğinde otomatik olarak yeni alt grup listesini çeker.

Adım 3: Ekrana Koyma

function FiltreBar() {
  const { anaGrup, altGrup, anaGrupDegistir, setAltGrup } = useFiltreler();
  const { data: anaGruplar } = useAnaGrupSecenekleri();
  const { data: altGruplar } = useAltGrupSecenekleri(anaGrup);

  return (
    <div className="filtre-bar">
      <select value={anaGrup} onChange={e => anaGrupDegistir(e.target.value)}>
        <option value="">Tüm Ana Gruplar</option>
        {anaGruplar?.map(g => <option key={g} value={g}>{g}</option>)}
      </select>

      <select value={altGrup} onChange={e => setAltGrup(e.target.value)}>
        <option value="">Tüm Alt Gruplar</option>
        {altGruplar?.map(g => <option key={g} value={g}>{g}</option>)}
      </select>
    </div>
  );
}

Kullanıcı Ne Yaşar?

1. Sayfa açıldı
   Ana Grup: [Tümü]      Alt Grup: [Tümü]     → 15.000 ürün

2. "Seramik" seçildi
   Ana Grup: [Seramik]    Alt Grup: [Tümü]     → 2.300 ürün
                          Seçenekler: Yer Seramiği, Duvar Fayansı, Mozaik

3. "Yer Seramiği" seçildi
   Ana Grup: [Seramik]    Alt Grup: [Yer Ser.] → 450 ürün

4. Ana Grup değiştirildi: "Boya"
   Ana Grup: [Boya]       Alt Grup: [Tümü]     → Alt Grup sıfırlandı!
                          Seçenekler: İç Cephe, Dış Cephe, Astar

Kullanıcı asla uyumsuz bir kombinasyon seçemez.

Aramayı Optimize Etme: Her Tuşa Basmada Sorgu Atma

Arama kutusuna yazarken her harf için veritabanına gitmek istemezsiniz. “Debounce” ile kullanıcı yazmayı bıraktıktan sonra sorgu atılır:

function useDebounce(deger, gecikme = 300) {
  const [gecikmeli, setGecikmeli] = useState(deger);

  useEffect(() => {
    const zamanlayici = setTimeout(() => setGecikmeli(deger), gecikme);
    return () => clearTimeout(zamanlayici);
  }, [deger, gecikme]);

  return gecikmeli;
}

// Kullanım:
const aramaMetni = useDebounce(filters.search, 300);
// → Kullanıcı yazmayı bıraktıktan 300ms sonra sorgu atar

Bu Yapıyla 2-3 Filtre Rahatça Çalışır

Ama 5+ bağımlı filtre zinciri (Ana Grup → Alt Grup → Marka → Renk → Boyut) olunca, 15.000+ üründe performans ve UX konularında daha ileri teknikler gerekir.

Biz böyle bir yapıyı production’da çalıştırıyoruz. İhtiyacınız olursa deneyimimizden faydalanabilirsiniz.


Bu yazı AstaFlow Case Study serisinin bir parçasıdır.