React ile Özel Sayfalandırma (Pagination) Nasıl Oluşturulur?
Giriş: Sayfalandırma Neden Önemli?
Web uygulamalarında büyük veri kümelerini kullanıcıya sunarken, tüm veriyi tek seferde yüklemek ve göstermek hem performans hem de kullanıcı deneyimi açısından ciddi sorunlara yol açabilir. İşte bu noktada sayfalandırma (pagination) devreye girer. Sayfalandırma, büyük bir veri setini daha küçük, yönetilebilir parçalara bölerek kullanıcıların bu veriler arasında kolayca gezinmesini sağlayan temel bir UI/UX çözümüdür. React gibi modern bir JavaScript kütüphanesi ile özel sayfalandırma bileşenleri oluşturmak, uygulamanızın ihtiyaçlarına tam olarak uyum sağlayan esnek ve güçlü çözümler sunar.
Kullanıcı Deneyimi
Bir web sayfasında binlerce öğenin aynı anda listelendiğini hayal edin. Bu durum, kullanıcının aradığı bilgiyi bulmasını zorlaştırır, sayfayı kaydırma (scrolling) işlemini yorucu hale getirir ve genel kullanıcı deneyimini olumsuz etkiler. Sayfalandırma, içeriği mantıksal sayfalara bölerek kullanıcıların daha odaklı bir şekilde gezinmesine olanak tanır. Kullanıcılar hangi sayfada olduklarını bilir, toplam kaç sayfa olduğunu görür ve belirli bir sayfaya doğrudan atlayabilirler. Bu, özellikle e-ticaret siteleri, bloglar, forumlar ve veri tabloları gibi yoğun içerikli uygulamalar için kritik öneme sahiptir.
Performans Optimizasyonu
Sayfalandırmanın en büyük faydalarından biri performans optimizasyonudur. Tüm veriyi veritabanından çekip istemciye göndermek ve ardından tarayıcıda render etmek, özellikle yüksek boyutlu veri setleri için uzun yükleme sürelerine ve bellek sorunlarına neden olabilir. Sayfalandırma sayesinde, sunucudan yalnızca mevcut sayfa için gerekli olan veri parçası istenir ve render edilir. Bu, hem sunucu yükünü azaltır hem de istemci tarafındaki sayfa yükleme süresini ve tarayıcı performansını önemli ölçüde artırır. Uygulamanızın daha hızlı ve daha duyarlı çalışmasını sağlar.
Veri Yönetimi
Sayfalandırma, veri yönetimini daha düzenli hale getirir. Geliştiriciler, sunucu tarafında veri tabanından belirli bir aralıktaki veriyi (örneğin, LIMIT ve OFFSET kullanarak) çekerek istemciye gönderir. Bu, hem sunucu tarafında daha verimli sorgular yazılmasına olanak tanır hem de istemci tarafında gelen verinin boyutunu kontrol altında tutar. Ayrıca, sayfalandırma, kullanıcıların belirli filtreler veya sıralama seçenekleri uyguladığında da bu seçeneklerin yalnızca ilgili sayfa verilerine uygulanmasını sağlayarak veri manipülasyonunu kolaylaştırır.
Temel Kavramlar ve Sayfalandırma Mantığı
Özel bir sayfalandırma bileşeni oluşturmadan önce, temel kavramları ve arkasındaki mantığı anlamak önemlidir. Bu kavramlar, sayfalandırma işlemini doğru bir şekilde uygulamak için birer yapı taşı görevi görür.
currentPage (Mevcut Sayfa)
currentPage, kullanıcının o an görüntülediği sayfanın numarasıdır. Genellikle 1’den başlar. Bu değer, kullanıcının hangi veri bloğunu görmesi gerektiğini belirlemede merkezi bir rol oynar. Sayfalandırma bileşenindeki düğmelere tıklandığında bu değer güncellenir.
itemsPerPage (Sayfa Başına Öğe Sayısı)
itemsPerPage, her bir sayfada kaç adet öğe (veri kaydı) gösterileceğini belirleyen sabit bir değerdir. Bu değer, uygulamanın tasarımına ve kullanıcının tercihine göre ayarlanabilir. Örneğin, bir blog sayfasında 10 yazı, bir e-ticaret sitesinde 20 ürün gösterilebilir. Bu değer, toplam veri kümesinin kaç sayfaya bölüneceğini hesaplamak için kullanılır.
totalItems (Toplam Öğe Sayısı)
totalItems, veri kümesindeki toplam öğe sayısıdır. Bu bilgi genellikle sunucu tarafından sağlanır ve sayfalandırma bileşeninin kaç adet sayfa numarası göstermesi gerektiğini hesaplamak için kritik öneme sahiptir.
totalPages (Toplam Sayfa Sayısı)
totalPages, totalItems ve itemsPerPage kullanılarak hesaplanan toplam sayfa sayısıdır. Bu değer, sayfalandırma bileşeninin kaç adet sayfa numarası düğmesi oluşturacağını belirler. Genellikle Math.ceil(totalItems / itemsPerPage) formülü ile hesaplanır, çünkü kalan öğeler için de yeni bir sayfa açılması gerekir.
Veri Dilimleme Mantığı
Sayfalandırmanın temelinde, büyük veri kümesini mevcut sayfa numarasına ve sayfa başına öğe sayısına göre dilimleme (slicing) mantığı yatar. Bu, genellikle JavaScript’teki slice() dizin metodunu kullanarak yapılır.
indexOfLastItem: Mevcut sayfadaki son öğenin dizinini (index) belirler. Formülü: currentPage itemsPerPage.
* indexOfFirstItem: Mevcut sayfadaki ilk öğenin dizinini belirler. Formülü: indexOfLastItem - itemsPerPage.
* currentItems: indexOfFirstItem ile indexOfLastItem arasındaki öğeleri içeren veri dilimidir. Bu dilim, kullanıcının o an gördüğü veriyi temsil eder.
Bu temel kavramları anladıktan sonra, React’ta bir sayfalandırma bileşeni oluşturmaya başlayabiliriz.
React’ta Temel Bir Sayfalandırma Bileşeni Oluşturma
React’ta özel bir sayfalandırma bileşeni oluşturmak, genellikle bir ana bileşen (örneğin, ProductList veya BlogPosts) ve bir alt bileşen (Pagination) kullanarak yapılır. Ana bileşen, veriyi yönetirken, alt bileşen sayfalandırma kontrollerini render eder ve sayfa değişikliklerini ana bileşene bildirir.
Veri Durumu ve Sayfalandırma Parametreleri
Öncelikle, uygulamanızın ana bileşeninde (örneğin, App.js veya ProductList.js) sayfalandırma için gerekli durumları yönetmemiz gerekir. useState hook’u bu durumları yönetmek için idealdir.
import React, { useState, useEffect } from 'react';
// Örnek bir veri kümesi
const allItems = Array.from({ length: 100 }, (_, i) => Öğe ${i + 1});
function ProductList() {
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10); // Her sayfada 10 öğe göster
// Toplam sayfa sayısını hesapla
const totalPages = Math.ceil(allItems.length / itemsPerPage);
// Mevcut sayfada gösterilecek öğeleri hesapla
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = allItems.slice(indexOfFirstItem, indexOfLastItem);
// Sayfa değiştirme fonksiyonu
const paginate = (pageNumber) => setCurrentPage(pageNumber);
return (
{currentItems.map((item, index) => (
- {item}
))}
{/ Sayfalandırma bileşeni buraya gelecek /}
);
}
export default ProductList;
Yukarıdaki örnekte:
* allItems: Uygulamanın tüm veri kümesini temsil eden basit bir dizi. Gerçek bir uygulamada bu veri genellikle bir API’den çekilir.
* currentPage: Mevcut sayfa numarasını tutar. Başlangıçta 1 olarak ayarlanmıştır.
* itemsPerPage: Her sayfada kaç öğe gösterileceğini belirler.
* totalPages: Toplam sayfa sayısıdır, allItems.length ve itemsPerPage kullanılarak hesaplanır.
* indexOfFirstItem, indexOfLastItem, currentItems: Mevcut sayfada gösterilecek öğeleri dilimlemek için kullanılan değişkenlerdir.
* paginate: currentPage durumunu güncelleyen bir fonksiyondur.
Sayfalandırma Mantığının Uygulanması
Pagination bileşenimiz, ProductList bileşeninden gerekli prop’ları alacak ve sayfa numarası düğmelerini render edecektir.
// Pagination.js
import React from 'react';
const Pagination = ({ itemsPerPage, totalItems, paginate, currentPage, totalPages }) => {
const pageNumbers = [];
for (let i = 1; i <= totalPages; i++) {
pageNumbers.push(i);
}
return (
}>
paginate(number)} href="#!" className="page-link">
{number}
))}
);
};
export default Pagination;
Bu temel Pagination bileşeni:
* pageNumbers dizisini oluşturur. Bu dizi, 1’den totalPages‘a kadar olan tüm sayfa numaralarını içerir.
* Bu pageNumbers dizisini haritalayarak her bir sayfa numarası için bir liste öğesi (
) oluşturur.*
onClick olayında, paginate prop’unu çağırarak ana bileşendeki currentPage durumunu günceller.* Mevcut sayfayı vurgulamak için
active sınıfını ekler.
Bu yapıyla, kullanıcı sayfa numaralarına tıkladıkça currentPage durumu değişecek, bu da ProductList bileşeninin yeniden render edilmesine ve currentItems‘ın güncellenmesine neden olacaktır. Sonuç olarak, listedeki öğeler mevcut sayfaya göre değişecektir.
Görsel Bileşenlerin Tasarımı
Yukarıdaki örnekte basit bir
- ve
yapısı kullandık. Gerçek bir uygulamada, bu bileşenleri CSS veya bir UI kütüphanesi (örneğin, Tailwind CSS, Bootstrap, Material-UI) ile stilize ederek daha çekici ve kullanışlı hale getirebilirsiniz.
Örneğin, Tailwind CSS ile basit bir stil:
/ index.css veya App.css /
.pagination {
display: flex;
list-style: none;
padding: 0;
margin: 20px 0;
justify-content: center;
}
.page-item {
margin: 0 5px;
}
.page-link {
display: block;
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
text-decoration: none;
color: #333;
cursor: pointer;
transition: background-color 0.2s;
}
.page-link:hover {
background-color: #f0f0f0;
}
.page-item.active .page-link {
background-color: #007bff;
color: white;
border-color: #007bff;
}
Bu CSS ile sayfalandırma düğmeleri daha düzenli ve interaktif görünecektir.
Gelişmiş Sayfalandırma Özellikleri
Temel bir sayfalandırma bileşeni oluşturmak iyi bir başlangıç olsa da, gerçek dünya uygulamaları genellikle daha gelişmiş özellikler gerektirir.
Sayfa Aralığı Yönetimi (Örn: 1 2 3 … 7 8 9)
Çok sayıda sayfa olduğunda (örneğin, 100 sayfa), tüm sayfa numaralarını listelemek sayfalandırma bileşenini çok uzun ve kullanışsız hale getirir. Bu durumda, belirli bir aralıktaki sayfa numaralarını gösterip aradaki sayfalar için “…” (üç nokta) kullanmak yaygın bir çözümdür.
Bu mantığı uygulamak için Pagination bileşenimizi güncelleyebiliriz:
// Pagination.js (Gelişmiş Versiyon)
import React from 'react';
const Pagination = ({ itemsPerPage, totalItems, paginate, currentPage, totalPages, pageRangeDisplayed = 5 }) => {
const pageNumbers = [];
// Sayfa numaralarını oluşturma mantığı
if (totalPages <= pageRangeDisplayed) {
// Toplam sayfa sayısı gösterilecek aralıktan küçükse tümünü göster
for (let i = 1; i <= totalPages; i++) {
pageNumbers.push(i);
}
} else {
// Dinamik sayfa aralığı oluşturma
const leftBound = Math.max(1, currentPage - Math.floor(pageRangeDisplayed / 2));
const rightBound = Math.min(totalPages, currentPage + Math.floor(pageRangeDisplayed / 2));
if (leftBound > 1) {
pageNumbers.push(1);
if (leftBound > 2) {
pageNumbers.push('...');
}
}
for (let i = leftBound; i <= rightBound; i++) {
pageNumbers.push(i);
}
if (rightBound < totalPages) {
if (rightBound < totalPages - 1) {
pageNumbers.push('...');
}
pageNumbers.push(totalPages);
}
}
return (
}>
paginate(currentPage - 1)} href="#!" className="page-link">
Önceki
Bu geliştirilmiş mantık, pageRangeDisplayed prop’u sayesinde yalnızca belirli bir sayıda sayfa numarasını gösterir ve gerektiğinde “…” ekler.
“İlk”, “Önceki”, “Sonraki”, “Son” Düğmeleri
Kullanıcı deneyimini iyileştirmek için genellikle sayfa numaralarının yanı sıra “İlk”, “Önceki”, “Sonraki” ve “Son” düğmeleri eklenir. Bu düğmeler, kullanıcıların sayfalar arasında daha hızlı gezinmesini sağlar.
Yukarıdaki gelişmiş Pagination bileşeni örneğinde “Önceki” ve “Sonraki” düğmeleri eklenmiştir. “İlk” ve “Son” düğmeleri de benzer şekilde eklenebilir:
// Pagination.js (İlk/Son düğmeleri eklenmiş)
// ... (önceki kod)
const Pagination = ({ itemsPerPage, totalItems, paginate, currentPage, totalPages, pageRangeDisplayed = 5 }) => {
// ... (pageNumbers oluşturma mantığı)
return (
}>
paginate(1)} href="#!" className="page-link">
İlk
{/ Önceki Sayfa Butonu /}
Bu düğmelerin disabled sınıfları, ilgili koşullar (örneğin, ilk sayfadayken “İlk” ve “Önceki” düğmelerinin pasif olması) sağlandığında kullanıcıya görsel geri bildirim sağlar ve hatalı tıklamaları önler.
Sayfa Boyutunu Değiştirme
Kullanıcılara her sayfada kaç öğe görmek istediklerini seçme olanağı sunmak, sayfalandırma deneyimini daha esnek hale getirir. Bu genellikle bir kutusu ile yapılır.
ProductList bileşenimize itemsPerPage değerini güncelleyen bir kutusu ekleyelim:
// ProductList.js (itemsPerPage seçeneği eklenmiş)
import React, { useState, useEffect } from 'react';
// ... allItems tanımı
function ProductList() {
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10);
const itemsPerPageOptions = [5, 10, 20, 50]; // Kullanıcının seçebileceği seçenekler
const totalPages = Math.ceil(allItems.length / itemsPerPage);
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = allItems.slice(indexOfFirstItem, indexOfLastItem);
const paginate = (pageNumber) => setCurrentPage(pageNumber);
const handleItemsPerPageChange = (e) => {
setItemsPerPage(Number(e.target.value));
setCurrentPage(1); // Sayfa boyutunu değiştirince ilk sayfaya dön
};
return (
{currentItems.map((item, index) => (
- {item}
))}
);
}
export default ProductList;
handleItemsPerPageChange fonksiyonu, itemsPerPage durumunu günceller ve aynı zamanda currentPage‘i 1’e sıfırlar. Bu, kullanıcı farklı bir sayfa boyutu seçtiğinde tutarlı bir deneyim sağlar.
URL Parametreleri ile Sayfa Durumunu Yönetme
Sayfalandırma durumunu URL’de saklamak (örneğin, ?page=2&limit=10), kullanıcıların mevcut sayfayı tarayıcı geçmişinde tutmasını, yer imi eklemesini veya bağlantıyı başkalarıyla paylaşmasını sağlar. Bu, uygulamaların daha kullanıcı dostu ve SEO uyumlu olmasına yardımcı olur. React Router kullanıyorsanız, useSearchParams hook’u bu işlem için idealdir.
// ProductList.js (URL parametreleri ile entegrasyon)
import React, { useState, useEffect } from 'react';
import { useSearchParams } from 'react-router-dom'; // React Router v6+ için
// ... allItems tanımı
function ProductList() {
const [searchParams, setSearchParams] = useSearchParams();
// URL'den sayfa ve limit değerlerini oku, yoksa varsayılanları kullan
const initialPage = Number(searchParams.get('page')) || 1;
const initialItemsPerPage = Number(searchParams.get('limit')) || 10;
const [currentPage, setCurrentPage] = useState(initialPage);
const [itemsPerPage, setItemsPerPage] = useState(initialItemsPerPage);
const itemsPerPageOptions = [5, 10, 20, 50];
const totalPages = Math.ceil(allItems.length / itemsPerPage);
// URL parametreleri değiştiğinde veya bileşen yüklendiğinde durumu güncelle
useEffect(() => {
setCurrentPage(Number(searchParams.get('page')) || 1);
setItemsPerPage(Number(searchParams.get('limit')) || 10);
}, [searchParams]);
// Sayfa veya limit değiştiğinde URL'yi güncelle
useEffect(() => {
const newSearchParams = new URLSearchParams();
newSearchParams.set('page', currentPage.toString());
newSearchParams.set('limit', itemsPerPage.toString());
setSearchParams(newSearchParams);
}, [currentPage, itemsPerPage, setSearchParams]);
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = allItems.slice(indexOfFirstItem, indexOfLastItem);
const paginate = (pageNumber) => {
if (pageNumber < 1 || pageNumber > totalPages) return; // Geçersiz sayfa numarası kontrolü
setCurrentPage(pageNumber);
};
const handleItemsPerPageChange = (e) => {
setItemsPerPage(Number(e.target.value));
setCurrentPage(1); // Sayfa boyutunu değiştirince ilk sayfaya dön
};
return (
{/ ... (önceki render kısmı) /}
);
}
export default ProductList;
Bu entegrasyonla:
* useSearchParams hook’u, URL sorgu parametrelerini okumak ve yazmak için kullanılır.
* initialPage ve initialItemsPerPage değerleri URL’den okunur. Eğer URL’de yoksa varsayılan değerler kullanılır.
* useEffect hook’ları, searchParams değiştiğinde React durumunu güncellemek ve currentPage veya itemsPerPage değiştiğinde URL’yi güncellemek için kullanılır. Bu, uygulamanızın URL ile senkronize kalmasını sağlar.
* paginate fonksiyonuna eklenen kontrol, geçersiz sayfa numaralarına (örneğin, 0 veya toplam sayfa sayısından büyük) gidilmesini engeller.
Bu kurulum, uygulamanızın sayfalandırma durumunu kalıcı hale getirir ve kullanıcıların daha iyi bir deneyim yaşamasını sağlar.
Performans ve Kullanıcı Deneyimi İpuçları
Özel bir sayfalandırma bileşeni oluştururken, sadece işlevselliğe değil, aynı zamanda performansa ve kullanıcı deneyimine de dikkat etmek önemlidir.
Lazy Loading / Infinite Scroll Karşılaştırması
Sayfalandırma, büyük veri kümelerini yönetmek için harika bir yöntemdir, ancak her zaman en iyi çözüm olmayabilir. Alternatif olarak, “Lazy Loading” (tembel yükleme) veya “Infinite Scroll” (sonsuz kaydırma) gibi teknikler de düşünülebilir.
* Sayfalandırma: Kullanıcıya toplam sayfa sayısını ve mevcut konumunu net bir şekilde gösterir. Belirli bir sayfaya doğrudan gitme olanağı sunar. Genellikle arama sonuçları, ürün katalogları gibi yapılandırılmış veriler için uygundur.
* Lazy Loading / Infinite Scroll: Kullanıcı sayfayı aşağı kaydırdıkça daha fazla içeriği dinamik olarak yükler. Kullanıcıların sürekli olarak yeni içerikle karşılaşmasını sağlar. Sosyal medya akışları, haber siteleri gibi sürekli akış halindeki içerikler için daha uygundur.
Seçim, uygulamanızın içeriğinin türüne ve kullanıcıların bu içerikle nasıl etkileşim kurmasını istediğinize bağlıdır.
SEO Dostu Sayfalandırma
Arama motorları, içeriğinizi keşfetmek ve dizine eklemek için sayfalandırma yapısını doğru bir şekilde anlamalıdır.
* Anlamsal HTML: Sayfalandırma bağlantılarınızın etiketleri olduğundan ve href niteliklerinin doğru URL’leri işaret ettiğinden emin olun. Örneğin, 2.
* rel="prev" ve rel="next": Her sayfanın bölümüne bu etiketleri ekleyerek arama motorlarına sayfaların birbirleriyle ilişkisini bildirin.
* Canonical URL: İlk sayfayı (veya ana sayfayı) canonical olarak belirtmek, yinelenen içerik sorunlarını önleyebilir.
* URL Parametreleri: Sayfa numarasını ve sayfa başına öğe sayısını URL parametrelerinde (örneğin, ?page=2&limit=10) tutmak, arama motorlarının her sayfayı ayrı bir kaynak olarak görmesine yardımcı olur.
Erişilebilirlik (ARIA)
Sayfalandırma bileşeninizin tüm kullanıcılar için erişilebilir olduğundan emin olun.
* Anlamsal Etiketler: nav etiketi, sayfalandırma navigasyonunu belirtmek için uygundur.
* ARIA Nitelikleri: aria-label veya aria-current="page" gibi ARIA nitelikleri, ekran okuyucularının sayfalandırma yapısını daha iyi anlamasına yardımcı olur. Örneğin:
* Klavye Navigasyonu: Kullanıcıların klavye ile sayfalar arasında gezinebildiğinden emin olun. Tab tuşu ile düğmeler arasında geçiş yapılabilmeli ve Enter tuşu ile sayfa değiştirilebilmelidir.
Stil ve Tasarım
Sayfalandırma bileşeninin tasarımı, uygulamanızın genel görünüm ve hissiyle uyumlu olmalıdır.
* Duyarlı Tasarım: Sayfalandırma bileşeninin farklı ekran boyutlarında (mobil, tablet, masaüstü) düzgün görünmesini ve çalışmasını sağlayın. Özellikle küçük ekranlarda, tüm sayfa numaralarını göstermek yerine “…” yapısını kullanmak daha önemlidir.
* Görsel Geri Bildirim: Tıklanabilir öğelerin üzerine gelindiğinde (hover) veya etkin (active) durumdayken görsel geri bildirim (renk değişimi, gölge vb.) sağlamak, kullanıcı deneyimini iyileştirir.
* Boşluk ve Hizalama: Düğmeler arasında yeterli boşluk bırakın ve hizalamayı doğru yapın, böylece düğmeler net bir şekilde ayrılır ve tıklaması kolay olur.
Sonuç
React ile özel sayfalandırma bileşenleri oluşturmak, uygulamanızın performansını artırmanın ve kullanıcı deneyimini zenginleştirmenin güçlü bir yoludur. Temel mantığı anlayarak ve useState, useEffect gibi React hook’larını kullanarak, veri kümenizi etkili bir şekilde yöneten ve kullanıcıların içeriğinizde rahatça gezinmesini sağlayan esnek ve özelleştirilebilir bir çözüm oluşturabilirsiniz.
Bu makalede, temel sayfalandırma mantığından başlayarak, “İlk”, “Önceki”, “Sonraki”, “Son” düğmeleri, sayfa aralığı yönetimi ve URL parametreleri ile entegrasyon gibi gelişmiş özelliklere kadar birçok konuyu ele aldık. Ayrıca, performans, SEO ve erişilebilirlik gibi kritik hususlara da değindik.
İleriye Dönük Adımlar
* Sunucu Tarafı Sayfalandırma: Gerçek dünya uygulamalarında, allItems dizisi genellikle sunucudan gelir. Sunucu tarafında page ve limit parametrelerine göre filtrelenmiş veriyi çekmek ve totalItems bilgisini de API yanıtında almak, daha ölçeklenebilir bir çözüm sunar.
* Test Etme: Bileşenlerinizi farklı senaryolarla (sıfır öğe, tek sayfa, çok sayıda sayfa) test ederek sağlamlığını sağlayın.
* UI Kütüphaneleri: Eğer sıfırdan stil yazmak istemiyorsanız, Chakra UI, Ant Design veya Material-UI gibi popüler UI kütüphanelerinin sayfalandırma bileşenlerini inceleyebilir ve uygulamanıza entegre edebilirsiniz. Bu kütüphaneler genellikle erişilebilirlik ve duyarlılık gibi konuları sizin için halleder.
Özel bir sayfalandırma bileşeni oluşturmak, React becerilerinizi geliştirirken aynı zamanda kullanıcılarınıza daha iyi bir deneyim sunmanızı sağlayacak değerli bir adımdır.
