---
title: "React'te Bağımlı Filtreler: Bir Filtreyi Seçince Diğerinin Güncellenmesi"
description: "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."
date: 2026-04-12
category: react-supabase
tags: ["react", "cascading-filter", "bağımlı-filtre", "supabase", "ux"]
url: https://mikroerp.dev/blog/react-cascading-baglimli-filtreler/
---

## 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.

```tsx
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:

```tsx
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

```tsx
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:

```tsx
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](/case-study) serisinin bir parçasıdır.*