Gereksinimler ve Ön Hazırlık
Projeye başlamadan önce bilgisayarınızda Node.js'in güncel bir sürümünün (LTS) yüklü olduğundan emin olmalısınız. React projenizi oluşturmak için Vite kullanmanızı öneririz, çünkü Vite, modern tarayıcılar için optimize edilmiş hızlı bir geliştirme ortamı sunar.
Geliştirme ortamınızı hazırlamak için terminalinizde şu komutları çalıştırabilirsiniz:
# Proje oluşturma
npm create vite@latest sonsuz-kaydirma -- --template react
cd sonsuz-kaydirma
npm install
npm run dev
Bu adımlardan sonra http://localhost:5173 adresinden projenizi görüntüleyebilirsiniz. Ayrıca veri çekme işlemleri için fetch API'sini veya axios kütüphanesini kullanabiliriz; bu rehberde yerleşik fetch API'si tercih edilmiştir.
Intersection Observer API Nedir?
IntersectionObserver, bir DOM elemanının, hedeflediğiniz bir kapsayıcı (genellikle viewport yani tarayıcı ekranı) ile kesişip kesişmediğini asenkron olarak izlemenizi sağlayan bir web API'sidir. Geleneksel scroll olay dinleyicilerinin (event listeners) aksine, ana iş parçacığını (main thread) yormaz ve performans sorunlarına yol açmaz.
Sonsuz kaydırma mantığında, listenin en altına görünmez bir "tetikleyici" (sentinel) eleman yerleştiririz. Bu eleman ekranda belirdiği anda, bir sonraki veri sayfasını yüklemek için tetikleyici fonksiyonumuzu çalıştırırız.
Adım Adım Sonsuz Kaydırma Mantığı
Sonsuz kaydırma yaparken izleyeceğimiz temel akış şu şekildedir: Verileri sayfalara ayırarak çek, mevcut listeyi güncelle ve listenin sonuna ulaşıldığında yeni sayfayı yükle. Aşağıdaki kod bloğunda, temel state yönetimini ve verilerin nasıl tutulacağını görebilirsiniz.
import { useState, useEffect, useRef } from 'react';
const InfiniteScroll = () => {
const [data, setData] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
const fetchItems = async (pageNumber) => {
setLoading(true);
const response = await fetch(`https://api.ornek.com/veriler?page=${pageNumber}`);
const newData = await response.json();
setData((prev) => [...prev, ...newData]);
setLoading(false);
};
useEffect(() => {
fetchItems(page);
}, [page]);
return (
{data.map((item) => ({item.title}))}
);
};
Bu kodda, page state'i değiştikçe yeni veriler çekilir. Ancak henüz bir tetikleyici mekanizmamız yok, bu yüzden bir sonraki adımda IntersectionObserver entegrasyonunu gerçekleştireceğiz.
Intersection Observer ile Tetikleyici Oluşturma
Şimdi, listenin sonuna bir referans ekleyerek bu referansın ekranda görünüp görünmediğini kontrol eden bir useEffect kancası (hook) yazalım. useRef kullanarak DOM elemanına erişeceğiz.
const observerTarget = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && !loading) {
setPage((prev) => prev + 1);
}
},
{ threshold: 1.0 }
);
if (observerTarget.current) {
observer.observe(observerTarget.current);
}
return () => {
if (observerTarget.current) {
observer.unobserve(observerTarget.current);
}
};
}, [loading]);
Burada threshold: 1.0 değeri, tetikleyici elemanın tamamı görünür olduğunda fonksiyonun çalışacağını belirtir. unobserve kullanımı, bileşen temizlenirken bellek sızıntılarını önlemek için kritiktir.
Performans ve Güvenlik Uyarıları
Dikkat: Sonsuz kaydırma yaparken API'nize gelen istekleri kontrol altında tutun. Kullanıcı çok hızlı kaydırdığında aynı sayfadan defalarca istek gitmemesi için
loadingdurumunu mutlaka kontrol edin. Ayrıca, dışarıdan gelen verileri render ederken XSS (Cross-Site Scripting) saldırılarına karşı veriyi doğrudan HTML olarak basmamaya, React'in varsayılan güvenli render yöntemlerini kullanmaya özen gösterin.
Aşağıdaki tablo, sonsuz kaydırma yöntemlerinin karşılaştırmasını göstermektedir:
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Intersection Observer | Yüksek performans, düşük CPU kullanımı | Eski tarayıcı desteği kısıtlı |
| Scroll Event Listener | Her tarayıcıda çalışır | Ana iş parçacığını yorar, performans düşürür |
Tam Uygulama: Bileşen Birleştirme
Tüm parçaları bir araya getirerek çalışan, temiz ve profesyonel bir sonsuz kaydırma bileşeni oluşturalım. Bu yapıda, yükleme durumunda bir "Yükleniyor..." göstergesi de ekliyoruz.
// App.jsx
import React, { useState, useEffect, useRef } from 'react';
export default function InfiniteScrollList() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
const loaderRef = useRef(null);
const loadMore = async () => {
setLoading(true);
// Gerçek bir API URL'si ile değiştirin
const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=10`);
const data = await res.json();
setItems((prev) => [...prev, ...data]);
setPage((prev) => prev + 1);
setLoading(false);
};
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && !loading) {
loadMore();
}
});
if (loaderRef.current) observer.observe(loaderRef.current);
return () => observer.disconnect();
}, [loading]);
return (
{items.map((item) => ({item.title}))}
{loading && Yükleniyor...
}
);
}
Bu kod bloğu, loaderRef elemanına ulaşıldığında otomatik olarak loadMore fonksiyonunu çağırır. loading durumu true olduğunda tetikleme devre dışı bırakılır, böylece mükerrer isteklerin önüne geçilir.
Sıkça Sorulan Sorular
Intersection Observer ile sonsuz kaydırma neden daha iyi?
Geleneksel scroll event listener'ları saniyede onlarca kez tetiklenir ve bu durum tarayıcıda ciddi performans kayıplarına neden olur. Intersection Observer ise sadece kesişme gerçekleştiğinde tarayıcı tarafından haber verilir, bu da onu çok daha verimli kılar.
Kullanıcı sayfayı çok hızlı kaydırırsa ne olur?
Kodumuzda kullandığımız !loading kontrolü, bir istek tamamlanmadan diğerinin başlamasını engeller. Bu, API'nize gereksiz yük binmesini önleyen temel bir koruma yöntemidir.
Mobil cihazlarda sonsuz kaydırma performansı nasıl etkilenir?
Mobil cihazlarda kaynaklar daha sınırlıdır. Intersection Observer, düşük CPU kullanımı sayesinde mobil cihazlarda daha akıcı bir kaydırma deneyimi sunar. Ancak, çok fazla DOM elemanı oluşturmamaya (örneğin sanal listeleme/virtualization kullanarak) dikkat etmelisiniz.
API'den veri gelmediğinde ne yapmalıyım?
API'nizden gelen veri dizisi boşaldığında, observer.disconnect() metodunu çağırarak tetikleyiciyi devre dışı bırakmalı ve kullanıcıya "Tüm veriler yüklendi" gibi bir mesaj göstermelisiniz.
Hata yönetimi nasıl yapılmalı?
fetch işlemini bir try-catch bloğu içine alarak, ağ hatalarını yakalamalı ve kullanıcıya anlamlı bir hata mesajı dönmelisiniz. Aksi takdirde, sessiz hatalar uygulamanızın takılı kalmasına neden olabilir.
Uyarı: Bu kod örneği eğitim amaçlıdır. Üretim ortamında (production) büyük ölçekli listelerle çalışırken, DOM'daki eleman sayısını sınırlamak için "Virtual List" (Sanal Liste) kütüphaneleriyle birlikte kullanılması önerilir.
Sanal Liste (Virtualization) ile Performansı Optimize Etme
Sonsuz kaydırma yapısında DOM elemanlarının sayısı arttıkça, tarayıcının bellek kullanımı ve yeniden boyama (reflow) maliyeti ciddi oranda artar. Binlerce öğeyi DOM'da tutmak, uygulamanın yavaşlamasına ve "donma" hissine neden olur. Bu sorunu çözmek için react-window veya react-virtuoso gibi kütüphanelerle sanal liste mantığını entegre etmeliyiz.
Sanal liste, yalnızca o an kullanıcının ekranında (viewport) görünen öğeleri DOM'a ekler. Kaydırma yapıldıkça, ekrandan çıkan öğeler DOM'dan kaldırılır ve yeni gelenler eklenir. İşte temel bir react-window entegrasyon örneği:
import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style, data }) => (
{data[index].title}
);
const VirtualizedList = ({ items }) => (
{Row}
);
Sonsuz Kaydırma İçin Test ve Hata Ayıklama Stratejileri
Sonsuz kaydırma mekanizmaları, asenkron veri çekme süreçleri nedeniyle hata yapmaya oldukça müsaittir. Geliştirme aşamasında şu stratejileri izleyerek uygulamanızın sağlamlığını artırabilirsiniz:
- Network Throttling: Chrome DevTools üzerinden "Network" sekmesine giderek bağlantı hızınızı "Slow 3G" olarak ayarlayın. Bu, veriler yüklenirken kullanıcıya gösterilecek
Loadingdurumlarının (skeleton screens) doğruluğunu test etmenizi sağlar. - Intersection Observer Gözlemcisi: Tarayıcı konsolunda
observer.thresholddeğerlerini değiştirerek tetikleyicinin tam olarak ne zaman çalıştığını görselleştirin. - Memory Leak Kontrolü: React DevTools kullanarak, bileşen her yeni veri setiyle güncellendiğinde gereksiz render işlemlerinin olup olmadığını "Profiler" sekmesinden inceleyin.
Yaygın Hata Senaryoları ve Çözümleri
| Hata Durumu | Olası Neden | Çözüm |
|---|---|---|
| Sonsuz döngü (sürekli veri çekme) | Tetikleyici eleman viewport dışına çıkmıyor. | Tetikleyiciye sabit bir yükseklik verin veya rootMargin değerini daraltın. |
| Veri mükerrer yükleniyor | State güncellemesi asenkron çalışırken tetikleyici tekrar çalışıyor. | isLoading boolean bayrağı ile veri çekme işlemi bitene kadar tetikleyiciyi kilitleyin. |
| Scroll pozisyonu kayboluyor | Liste güncellendiğinde DOM boyutu aniden değişiyor. | Sanal liste kütüphaneleri kullanarak scroll pozisyonunu koruyun. |
Bu hata ayıklama adımları, uygulamanızın gerçek kullanıcı senaryolarında beklenmedik şekilde çökmesini engeller. Özellikle useEffect içerisindeki cleanup fonksiyonlarını doğru yapılandırmak, bileşen unmount olduğunda gözlemcinin (observer) bağlantısını kesmek için kritiktir.
Sonuç
React ile Intersection Observer kullanarak sonsuz kaydırma sayfası yapmak, hem modern standartlara uygun bir yaklaşım hem de kullanıcı deneyimini iyileştiren kritik bir beceridir. Bu rehberde, bir tetikleyicinin nasıl oluşturulacağını, verilerin asenkron olarak nasıl yönetileceğini ve performansın nasıl korunacağını öğrendiniz.
Bir sonraki adım olarak, bu yapıya "Sanal Liste" (Virtualization) mantığını ekleyerek çok daha büyük veri setlerinde bile uygulamanızın akıcı kalmasını sağlayabilirsiniz. Başarılı kodlamalar dileriz.


Yorumlar (0)
Yorum Yaz