React İle Intersection Observer Kullanarak Sonsuz Kaydırma Sayfası Nasıl Yapılır?

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 loading durumunu 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 Loading durumlarının (skeleton screens) doğruluğunu test etmenizi sağlar.
  • Intersection Observer Gözlemcisi: Tarayıcı konsolunda observer.threshold değ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.

Bu yazıya tepkinizi paylaşın:
Zeynep Kaya

Ev ekonomisi ve kişisel organizasyon üzerine birçok yayın yönettim. Okuyucuların günlük yaşam kalitesini artıracak uygulanabilir çözümler üretmeyi hedefliyorum.

Yorumlar (0)

Yorum Yaz