Gereksinimler ve Ön Hazırlık
Projeye başlamadan önce bilgisayarınızda Node.js (v18 veya üzeri) yüklü olmalıdır. React projeleri için Vite kullanmak, geliştirme sürecinde hız ve performans avantajı sağlar. Çalışma ortamınızı hazırlamak için terminalinizde aşağıdaki komutları izleyin:
# Yeni bir React projesi oluşturun
npm create vite@latest dinamik-filtreleme -- --template react
cd dinamik-filtreleme
npm install
npm run dev
Bu adımlardan sonra projeniz tarayıcıda 5173 portunda çalışmaya başlayacaktır. Temel kütüphane olarak React'in kendi "hooks" (kanca) yapısını (useState, useMemo) kullanacağız, bu sayede ekstra bir paket yüklemeden yüksek performans elde edeceğiz.
Veri Yapısını Tanımlama ve State Yönetimi
Filtreleme işleminin ilk adımı, verinin nasıl saklanacağını ve yönetileceğini belirlemektir. Gerçek senaryolarda veriler genellikle bir API'den gelir, ancak biz burada yerel bir dizi üzerinde işlem yapacağız. State yönetimi için useState kullanarak arama terimini ve filtreleme kriterlerini tutacağız.
import { useState } from 'react';
const veriler = [
{ id: 1, isim: 'React Eğitimi', kategori: 'Frontend' },
{ id: 2, isim: 'Node.js Temelleri', kategori: 'Backend' },
{ id: 3, isim: 'TypeScript Rehberi', kategori: 'Frontend' },
{ id: 4, isim: 'PostgreSQL İpuçları', kategori: 'Veritabanı' }
];
export default function FiltrelemeBileseni() {
const [arama, setArama] = useState('');
const [kategori, setKategori] = useState('Hepsi');
// ... sonraki adımlar
}
Burada arama değişkeni kullanıcının girdiği metni, kategori değişkeni ise seçilen filtreyi tutar. Bu iki değişken, bileşenin yeniden render edilmesini tetikleyen tetikleyicilerdir.
Adım Adım Filtreleme Mantığı: useMemo Kullanımı
Filtreleme işlemini her render sırasında yeniden hesaplamak performans kaybına yol açabilir. useMemo kancası, yalnızca bağımlılıklar (arama veya kategori) değiştiğinde hesaplama yaparak uygulamanın hızını korur. Bu, büyük veri setlerinde "lag" (gecikme) yaşanmasını engeller.
import { useMemo } from 'react';
const filtrelenmisVeri = useMemo(() => {
return veriler.filter((item) => {
const isimUyumu = item.isim.toLowerCase().includes(arama.toLowerCase());
const kategoriUyumu = kategori === 'Hepsi' || item.kategori === kategori;
return isimUyumu && kategoriUyumu;
});
}, [arama, kategori]);
Bu kod bloğu, veriler dizisini tarar ve hem isim hem de kategori kriterlerine uyan öğeleri döndürür. toLowerCase() kullanımı, aramanın büyük/küçük harf duyarlılığını ortadan kaldırarak kullanıcı deneyimini iyileştirir.
Kullanıcı Arayüzü ve Girdi Kontrolleri
Kullanıcının filtreleme kriterlerini girebileceği bir arayüz oluşturmak, React'in "Controlled Components" (Kontrollü Bileşenler) mantığı ile yapılır. Input ve Select öğelerini state ile bağlayarak verinin her an güncel kalmasını sağlarız.
return (
setArama(e.target.value)}
/>
setKategori(e.target.value)}>
Hepsi
Frontend
Backend
{filtrelenmisVeri.map(item => (
- {item.isim} - {item.kategori}
))}
);
Burada key prop'u kullanmak, React'in liste öğelerini birbirinden ayırt etmesi ve DOM güncellemelerini optimize etmesi için zorunludur. Yanlış veya mükerrer key kullanımı performans sorunlarına yol açar.
Filtreleme Yöntemlerinin Karşılaştırılması
Dinamik filtreleme yaparken farklı yaklaşımlar tercih edilebilir. Aşağıdaki tablo, yaygın yöntemlerin avantaj ve dezavantajlarını özetlemektedir.
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| useMemo (Client-side) | Çok hızlı, sunucu yükü yok | Çok büyük veride (10k+ satır) yavaşlar |
| API Filtreleme (Server-side) | Büyük veriler için ideal | Sunucu maliyeti ve ağ gecikmesi |
Güvenlik ve Hata Yönetimi
Kritik Güvenlik Uyarısı: Kullanıcıdan alınan arama girdilerini doğrudan DOM'a yansıtırken XSS (Cross-Site Scripting) saldırılarına karşı dikkatli olunmalıdır. React, varsayılan olarak girdileri "escape" ederek bu riski azaltır ancak
dangerouslySetInnerHTMLgibi yöntemlerden kaçınmalısınız. Ayrıca, büyük veri setlerinde "Debounce" (gecikmeli işlem) tekniği kullanarak sunucuya veya hesaplama motoruna aşırı yük binmesini engelleyin.
Debounce tekniği, kullanıcı yazarken her tuş vuruşunda filtreleme yapılması yerine, yazma işlemi bittikten 300ms sonra işlemin tetiklenmesini sağlar.
Sıkça Sorulan Sorular
Filtreleme neden çalışmıyor?
Genellikle state güncelleme fonksiyonunun asenkron yapısı veya yanlış bağımlılık dizisi (dependency array) nedeniyle oluşur. console.log ile verinin filtreleme fonksiyonuna ulaşıp ulaşmadığını kontrol edin.
Çok büyük veri setlerinde ne yapmalıyım?
Veri setiniz 5000 öğeyi geçiyorsa, "Windowing" veya "Virtualization" tekniklerini (örneğin react-window kütüphanesi) kullanarak sadece ekranda görünen öğelerin render edilmesini sağlamalısınız.
Büyük/küçük harf duyarlılığını nasıl kapatırım?
Her iki tarafı da toLowerCase() veya toUpperCase() metodundan geçirerek metinleri normalize etmek standart çözümdür.
Debounce nedir ve neden gereklidir?
Debounce, bir fonksiyonun arka arkaya çok hızlı çağrılmasını engelleyen bir teknik olup, özellikle arama kutularında performans optimizasyonu için elzemdir.
State'i neden useMemo ile sarmalıyoruz?
Bileşen her render edildiğinde filtreleme mantığının yeniden çalışmasını engellemek ve gereksiz işlemci yükünden kaçınmak için kullanılır.
İleri Seviye Filtreleme: Çoklu Kriter ve Dinamik Sorgu Oluşturma
Basit bir metin araması çoğu zaman yeterli olsa da, profesyonel uygulamalarda birden fazla kriteri (kategori, fiyat aralığı, tarih vb.) aynı anda filtrelemeniz gerekebilir. Bu durumda, her bir filtre kriterini ayrı bir state değişkeninde tutmak yerine, tek bir filters nesnesi kullanmak kodun okunabilirliğini ve yönetilebilirliğini artırır.
Aşağıdaki örnekte, hem metin hem de kategori bazlı filtreleme yapan merkezi bir yapı kurguluyoruz:
const [filters, setFilters] = useState({ query: '', category: 'all' });
const filteredData = useMemo(() => {
return data.filter(item => {
const matchesQuery = item.name.toLowerCase().includes(filters.query.toLowerCase());
const matchesCategory = filters.category === 'all' || item.category === filters.category;
return matchesQuery && matchesCategory;
});
}, [data, filters]);
Performans İzleme ve Profiling
Filtreleme mantığınızın ne kadar sürede çalıştığını ölçmek, özellikle büyük veri setlerinde darboğazları tespit etmek için kritiktir. React DevTools içerisindeki "Profiler" sekmesini kullanarak, useMemo kancasının gerçekten gereksiz hesaplamaları engelleyip engellemediğini gözlemleyebilirsiniz.
Eğer filtreleme işlemi 16ms'den (60 FPS için gereken süre) uzun sürüyorsa, şu stratejileri uygulayabilirsiniz:
- Web Workers: Filtreleme işlemini ana iş parçacığından (main thread) ayırarak arayüzün donmasını engeller.
- Virtualization:
react-windowveyareact-virtualizedkütüphanelerini kullanarak sadece ekranda görünen öğelerin DOM'a basılmasını sağlayın. - Memoization Derinliği: Eğer filtreleme fonksiyonunuz çok karmaşıksa, veriyi parçalara ayırarak (chunking) işleyin.
Alternatif Yaklaşım: TanStack Table (React Table) Kullanımı
Kendi filtreleme mantığınızı yazmak öğretici olsa da, kurumsal projelerde TanStack Table gibi olgun kütüphaneler kullanmak, sıralama, filtreleme ve sayfalama gibi karmaşık işleri standart hale getirir. Bu kütüphaneler, filtreleme mantığını "headless" (arayüzden bağımsız) bir yapıda sunduğu için kendi tasarımınızı özgürce uygulamanıza olanak tanır.
Not: Kütüphane kullanmadan önce, projenizin karmaşıklığını değerlendirin. Eğer sadece basit bir arama çubuğuna ihtiyacınız varsa, kütüphane eklemek paket boyutunuzu (bundle size) gereksiz yere artıracaktır.
Basit bir tablo filtreleme örneği:
import { useReactTable, getCoreRowModel, getFilteredRowModel } from '@tanstack/react-table';
const table = useReactTable({
data,
columns,
state: { globalFilter: filterValue },
onGlobalFilterChange: setFilterValue,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
});
Bu yaklaşım, filtreleme mantığını merkezi bir tablo örneği üzerinden yönetmenizi sağlayarak, manuel filter() fonksiyonları yazma ihtiyacını ortadan kaldırır ve hata payını minimize eder.
Sonuç
React ile dinamik veri filtreleme bileşeni oluşturmak, bileşen mimarisini ve kanca yapısını anlamak için harika bir pratik çalışmasıdır. Bu rehberde, useState ile durum yönetimi yapmayı, useMemo ile performansı optimize etmeyi ve kullanıcı girdilerini güvenli bir şekilde işlemeyi öğrendiniz. Bir sonraki adım olarak, bu bileşeni bir API'ye bağlayarak "Server-side Pagination" (sunucu taraflı sayfalama) konusunu araştırmanızı öneririm.


Yorumlar (0)
Yorum Yaz