{"id":34387,"date":"2025-11-16T02:40:41","date_gmt":"2025-11-15T23:40:41","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=34387"},"modified":"2025-11-16T02:40:41","modified_gmt":"2025-11-15T23:40:41","slug":"react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/","title":{"rendered":"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?"},"content":{"rendered":"<p><body><\/p>\n<h2>React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?<\/h2>\n<p>Web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimini zenginle\u015ftiren ve veri yo\u011fun i\u00e7erikleri daha y\u00f6netilebilir hale getiren modern tekniklerden biri, &#8220;sonsuz kayd\u0131rma&#8221; (infinite scroll) \u00f6zelli\u011fidir. \u00d6zellikle resim galerileri, \u00fcr\u00fcn listeleri veya sosyal medya ak\u0131\u015flar\u0131 gibi s\u00fcrekli yeni i\u00e7erik g\u00f6sterilmesi gereken durumlarda sonsuz kayd\u0131rma, sayfalama (pagination) y\u00f6ntemine k\u0131yasla daha ak\u0131c\u0131 ve kesintisiz bir deneyim sunar. Kullan\u0131c\u0131lar\u0131n bir sonraki sayfa d\u00fc\u011fmesine t\u0131klamak yerine, sadece a\u015fa\u011f\u0131 kayd\u0131rarak yeni i\u00e7eri\u011fe ula\u015fmas\u0131, etkile\u015fimi art\u0131r\u0131r ve y\u00fckleme s\u00fcrelerini alg\u0131sal olarak azalt\u0131r.<\/p>\n<p>Bu makalede, modern bir JavaScript k\u00fct\u00fcphanesi olan React ve g\u00fc\u00e7l\u00fc bir CSS d\u00fczenleme arac\u0131 olan CSS Grid&#8217;i bir araya getirerek dinamik, duyarl\u0131 ve sonsuz kayd\u0131rmal\u0131 bir resim galerisi uygulamas\u0131n\u0131n nas\u0131l in\u015fa edilece\u011fini ad\u0131m ad\u0131m inceleyece\u011fiz. React&#8217;in bile\u015fen tabanl\u0131 yap\u0131s\u0131 ve durum y\u00f6netimi yetenekleri, uygulaman\u0131n dinamik veri ak\u0131\u015f\u0131n\u0131 kolayca y\u00f6netmemizi sa\u011flarken, CSS Grid ise galeri d\u00fczenini esnek ve performant bir \u015fekilde olu\u015fturmam\u0131z i\u00e7in ideal bir ara\u00e7 olacakt\u0131r.<\/p>\n<p>Uygulamam\u0131z\u0131n temel amac\u0131, bir API&#8217;den resim verilerini \u00e7ekmek, bu resimleri bir \u0131zgara d\u00fczeninde sergilemek ve kullan\u0131c\u0131 sayfan\u0131n sonuna yakla\u015ft\u0131\u011f\u0131nda otomatik olarak daha fazla resim y\u00fckleyerek sonsuz kayd\u0131rma etkisini yaratmakt\u0131r. Bu s\u00fcre\u00e7te, React&#8217;in <code>useState<\/code> ve <code>useEffect<\/code> kancalar\u0131n\u0131, olay dinleyicilerini ve modern CSS Grid \u00f6zelliklerini derinlemesine ele alaca\u011f\u0131z. Performans ve kullan\u0131c\u0131 deneyimi gibi \u00f6nemli noktalar\u0131 da g\u00f6z \u00f6n\u00fcnde bulundurarak, sadece \u00e7al\u0131\u015fan de\u011fil, ayn\u0131 zamanda optimize edilmi\u015f bir \u00e7\u00f6z\u00fcm sunmay\u0131 hedefliyoruz.<\/p>\n<p>### Sonsuz Kayd\u0131rma Nedir ve Neden Kullan\u0131l\u0131r?<\/p>\n<p>Sonsuz kayd\u0131rma, bir web sayfas\u0131n\u0131n sonuna gelindi\u011finde otomatik olarak yeni i\u00e7erik y\u00fcklemesi prensibine dayan\u0131r. Bu, kullan\u0131c\u0131lar\u0131n bir sonraki sayfa d\u00fc\u011fmesine t\u0131klamak zorunda kalmadan s\u00fcrekli yeni i\u00e7erik ke\u015ffetmesine olanak tan\u0131r. Kullan\u0131c\u0131lar\u0131n dikkatini da\u011f\u0131tmadan i\u00e7eri\u011fe odaklanmalar\u0131n\u0131 sa\u011flamas\u0131, \u00f6zellikle mobil cihazlarda ekran alan\u0131n\u0131n k\u0131s\u0131tl\u0131 oldu\u011fu durumlarda b\u00fcy\u00fck avantaj sa\u011flar.<\/p>\n<p><strong>Avantajlar\u0131:<\/strong><br \/>\n*   <strong>Geli\u015fmi\u015f Kullan\u0131c\u0131 Deneyimi:<\/strong> Kesintisiz bir ak\u0131\u015f sunarak kullan\u0131c\u0131 etkile\u015fimini art\u0131r\u0131r.<br \/>\n*   <strong>Daha Az T\u0131klama:<\/strong> Kullan\u0131c\u0131lar\u0131n sayfa ge\u00e7i\u015fleri i\u00e7in t\u0131klama yapmas\u0131n\u0131 gerektirmez.<br \/>\n*   <strong>Mobil Dostu:<\/strong> K\u00fc\u00e7\u00fck ekranlarda gezinmeyi kolayla\u015ft\u0131r\u0131r.<br \/>\n*   <strong>Daha Fazla \u0130\u00e7erik Ke\u015ffi:<\/strong> Kullan\u0131c\u0131lar\u0131n potansiyel olarak daha fazla i\u00e7eri\u011fi g\u00f6rmesini sa\u011flar.<\/p>\n<p><strong>Dezavantajlar\u0131 (ve nas\u0131l \u00fcstesinden gelinece\u011fi):<\/strong><br \/>\n*   <strong>Sayfa Altbilgisine Ula\u015famama:<\/strong> Sonsuz i\u00e7erik nedeniyle altbilgiye ula\u015fmak zorla\u015fabilir. Bu durum, \u00f6nemli bilgileri (ileti\u015fim, gizlilik politikas\u0131 vb.) yan men\u00fclere veya sabit bir ba\u015fl\u0131\u011fa yerle\u015ftirerek \u00e7\u00f6z\u00fclebilir.<br \/>\n*   <strong>Geri D\u00f6n\u00fc\u015f Sorunlar\u0131:<\/strong> Kullan\u0131c\u0131lar sayfada \u00e7ok a\u015fa\u011f\u0131ya kayd\u0131ktan sonra geri d\u00f6nd\u00fcklerinde, \u00f6nceki konumlar\u0131n\u0131 kaybetme riskiyle kar\u015f\u0131la\u015fabilirler. Taray\u0131c\u0131 ge\u00e7mi\u015fi API&#8217;leri veya durum y\u00f6netimi ile bu sorun hafifletilebilir.<br \/>\n*   <strong>Performans Sorunlar\u0131:<\/strong> \u00c7ok fazla DOM \u00f6\u011fesi sayfa performans\u0131n\u0131 d\u00fc\u015f\u00fcrebilir. Sanalla\u015ft\u0131rma (virtualization) ve optimize edilmi\u015f bile\u015fenler ile bu sorunlar giderilebilir.<\/p>\n<p>Bu makalede, sonsuz kayd\u0131rman\u0131n avantajlar\u0131ndan yararlan\u0131rken potansiyel dezavantajlar\u0131n\u0131 da en aza indirmeye odaklanaca\u011f\u0131z.<\/p>\n<p>### Proje Kurulumu ve Temel Yap\u0131<\/p>\n<p>Uygulamam\u0131z\u0131 geli\u015ftirmeye ba\u015flamadan \u00f6nce, React projemizi olu\u015ftural\u0131m. Bunun i\u00e7in <code>create-react-app<\/code> veya Vite gibi ara\u00e7lar\u0131 kullanabiliriz. Biz burada daha hafif ve h\u0131zl\u0131 oldu\u011fu i\u00e7in Vite&#8217;\u0131 tercih edece\u011fiz.<\/p>\n<pre><code class=\"language-bash\"># Vite ile yeni bir React projesi olu\u015fturma\nnpm create vite@latest infinite-scroll-gallery -- --template react\n\n<h2>Proje dizinine git<\/h2>\ncd infinite-scroll-gallery\n\n<h2>Ba\u011f\u0131ml\u0131l\u0131klar\u0131 y\u00fckle<\/h2>\nnpm install\n\n<h2>Projeyi ba\u015flat<\/h2>\nnpm run dev<\/code><\/pre>\n<p>Projemizi ba\u015flatt\u0131ktan sonra, taray\u0131c\u0131n\u0131zda <code>http:\/\/localhost:5173<\/code> (veya benzeri bir port) adresinde varsay\u0131lan React uygulamas\u0131n\u0131 g\u00f6rmelisiniz. \u015eimdi projemizin ana dosyalar\u0131n\u0131 d\u00fczenlemeye ba\u015flayal\u0131m. <code>src<\/code> klas\u00f6r\u00fcn\u00fcn alt\u0131nda <code>components<\/code> ad\u0131nda bir klas\u00f6r olu\u015ftural\u0131m ve bile\u015fenlerimizi buraya yerle\u015ftirelim.<\/p>\n<pre><code class=\"language-\">src\/\n\u251c\u2500\u2500 App.jsx\n\u251c\u2500\u2500 main.jsx\n\u251c\u2500\u2500 index.css\n\u2514\u2500\u2500 components\/\n    \u251c\u2500\u2500 GalleryGrid.jsx\n    \u251c\u2500\u2500 ImageCard.jsx<\/code><\/pre>\n<p><code>App.jsx<\/code> ana bile\u015fenimiz olacak, <code>GalleryGrid.jsx<\/code> resimleri bir \u0131zgarada g\u00f6sterecek, ve <code>ImageCard.jsx<\/code> ise tek bir resmi temsil edecek.<\/p>\n<p>### Resim Verilerini \u00c7ekme ve Durum Y\u00f6netimi<\/p>\n<p>Sonsuz kayd\u0131rmal\u0131 bir galeri i\u00e7in en \u00f6nemli ad\u0131mlardan biri, resim verilerini bir API&#8217;den \u00e7ekmek ve bu verileri React bile\u015feninin durumunda y\u00f6netmektir. Genellikle Unsplash, Pexels veya Pixabay gibi \u00fccretsiz resim API&#8217;leri kullan\u0131labilir. Bu \u00f6rnekte, ger\u00e7ek bir API yerine basit bir mock (sahte) API \u00e7a\u011fr\u0131s\u0131 yaparak konsepti a\u00e7\u0131klayaca\u011f\u0131z. Ancak ger\u00e7ek bir uygulamada bir API anahtar\u0131 alman\u0131z ve API&#8217;nin dok\u00fcmantasyonuna g\u00f6re istek yapman\u0131z gerekecektir.<\/p>\n<p><code>App.jsx<\/code> dosyam\u0131z\u0131 a\u015fa\u011f\u0131daki gibi g\u00fcncelleyelim:<\/p>\n<pre><code class=\"language-jsx\">\/\/ src\/App.jsx\nimport React, { useState, useEffect, useCallback } from 'react';\nimport GalleryGrid from '.\/components\/GalleryGrid';\nimport '.\/App.css'; \/\/ Global CSS dosyam\u0131z\n\nconst App = () => {\n  const [images, setImages] = useState([]);\n  const [page, setPage] = useState(1);\n  const [loading, setLoading] = useState(false);\n  const [hasMore, setHasMore] = useState(true); \/\/ Daha fazla resim olup olmad\u0131\u011f\u0131n\u0131 kontrol eder\n\n  \/\/ Mock API \u00e7a\u011fr\u0131s\u0131 - Ger\u00e7ek bir uygulamada bir API'ye istek atacaks\u0131n\u0131z\n  const fetchImages = useCallback(async () => {\n    if (loading || !hasMore) return; \/\/ Zaten y\u00fckleniyorsa veya daha fazla resim yoksa tekrar istek atma\n\n    setLoading(true);\n    console.log(<code>Fetching images for page ${page}...<\/code>);\n\n    try {\n      \/\/ Ger\u00e7ek bir API \u00e7a\u011fr\u0131s\u0131 yerine setTimeout ile sim\u00fcle ediyoruz\n      const response = await new Promise(resolve => setTimeout(() => {\n        const newImages = Array.from({ length: 15 }, (_, i) => ({\n          id: (page - 1) * 15 + i,\n          src: <code>https:\/\/picsum.photos\/id\/${(page - 1) * 15 + i + 10}\/400\/300<\/code>, \/\/ Picsum.photos'tan rastgele resimler\n          alt: <code>Resim ${(page - 1) * 15 + i + 10}<\/code>,\n        }));\n        resolve({ data: newImages });\n      }, 1000)); \/\/ 1 saniye gecikme ile y\u00fckleme sim\u00fclasyonu\n\n      if (response.data.length === 0 || page >= 5) { \/\/ \u00d6rnek olarak 5 sayfadan sonra resim bitiyor\n        setHasMore(false);\n      } else {\n        setImages(prevImages => [...prevImages, ...response.data]);\n        setPage(prevPage => prevPage + 1);\n      }\n    } catch (error) {\n      console.error(\"Resimler \u00e7ekilirken bir hata olu\u015ftu:\", error);\n      \/\/ Hata durumunda kullan\u0131c\u0131ya bilgi verilebilir\n    } finally {\n      setLoading(false);\n    }\n  }, [page, loading, hasMore]); \/\/ Ba\u011f\u0131ml\u0131l\u0131klar\u0131 ekliyoruz\n\n  \/\/ Bile\u015fen y\u00fcklendi\u011finde ve sayfa de\u011fi\u015fti\u011finde resimleri \u00e7ek\n  useEffect(() => {\n    fetchImages();\n  }, []); \/\/ Sadece ilk render'da \u00e7a\u011f\u0131r\u0131yoruz, scroll event'i ile tetiklenecek\n\n  \/\/ Kayd\u0131rma olay\u0131n\u0131 dinle\n  useEffect(() => {\n    const handleScroll = () => {\n      \/\/ Sayfan\u0131n alt k\u0131sm\u0131na ne kadar yakla\u015ft\u0131\u011f\u0131m\u0131z\u0131 kontrol et\n      const { scrollTop, clientHeight, scrollHeight } = document.documentElement;\n\n      \/\/ Kullan\u0131c\u0131 sayfan\u0131n %80'ine ula\u015ft\u0131\u011f\u0131nda yeni resimleri \u00e7ek\n      if (scrollTop + clientHeight >= scrollHeight * 0.8 && !loading && hasMore) {\n        fetchImages();\n      }\n    };\n\n    window.addEventListener('scroll', handleScroll);\n    return () => window.removeEventListener('scroll', handleScroll); \/\/ Temizleme fonksiyonu\n  }, [loading, hasMore, fetchImages]); \/\/ Ba\u011f\u0131ml\u0131l\u0131klar\u0131 ekliyoruz\n\n  return (\n    <div className=\"App\">\n      \n      <GalleryGrid images={images} \/>\n      {loading && <p className=\"loading-indicator\">Resimler y\u00fckleniyor...<\/p>}\n      {!hasMore && !loading && images.length > 0 && (\n        <p className=\"no-more-images\">Daha fazla resim yok.<\/p>\n      )}\n      {!hasMore && !loading && images.length === 0 && (\n        <p className=\"no-images-found\">G\u00f6sterilecek resim bulunamad\u0131.<\/p>\n      )}\n    <\/div>\n  );\n};\n\nexport default App;<\/code><\/pre>\n<p><strong>Kod A\u00e7\u0131klamas\u0131:<\/strong><\/p>\n<p>*   <strong><code>useState<\/code> Kancalar\u0131:<\/strong><br \/>\n    *   <code>images<\/code>: \u00c7ekilen t\u00fcm resimleri tutan bir dizi. Yeni resimler eklendik\u00e7e bu diziye eklenir.<br \/>\n    *   <code>page<\/code>: API&#8217;den hangi sayfan\u0131n \u00e7ekilece\u011fini belirten bir say\u0131. Her ba\u015far\u0131l\u0131 \u00e7ekimden sonra art\u0131r\u0131l\u0131r.<br \/>\n    *   <code>loading<\/code>: Resim \u00e7ekme i\u015fleminin devam edip etmedi\u011fini g\u00f6steren bir boolean. Bu, ayn\u0131 anda birden fazla istek at\u0131lmas\u0131n\u0131 engeller.<br \/>\n    *   <code>hasMore<\/code>: Daha fazla resim olup olmad\u0131\u011f\u0131n\u0131 g\u00f6steren bir boolean. API&#8217;den bo\u015f bir dizi geldi\u011finde veya belirli bir sayfa s\u0131n\u0131r\u0131na ula\u015f\u0131ld\u0131\u011f\u0131nda <code>false<\/code> olarak ayarlan\u0131r.<br \/>\n*   <strong><code>fetchImages<\/code> Fonksiyonu:<\/strong><br \/>\n    *   <code>useCallback<\/code> ile sarmalanm\u0131\u015ft\u0131r. Bu, fonksiyonun sadece ba\u011f\u0131ml\u0131l\u0131klar\u0131 de\u011fi\u015fti\u011finde yeniden olu\u015fturulmas\u0131n\u0131 sa\u011flayarak performans\u0131 art\u0131r\u0131r ve <code>useEffect<\/code> i\u00e7indeki sonsuz d\u00f6ng\u00fcleri engeller.<br \/>\n    *   <code>loading<\/code> veya <code>hasMore<\/code> durumu <code>false<\/code> ise, gereksiz API \u00e7a\u011fr\u0131lar\u0131n\u0131 \u00f6nlemek i\u00e7in erken \u00e7\u0131kar.<br \/>\n    *   <code>setLoading(true)<\/code> ile y\u00fckleme durumunu ba\u015flat\u0131r.<br \/>\n    *   <code>setTimeout<\/code> kullanarak 1 saniyelik bir gecikmeyle sahte resim verileri olu\u015fturur. Ger\u00e7ek bir uygulamada burada <code>fetch<\/code> veya <code>axios<\/code> ile bir API&#8217;ye HTTP iste\u011fi yapacaks\u0131n\u0131z.<br \/>\n    *   Gelen resimleri <code>setImages<\/code> ile mevcut resim dizisine ekler (<code>prevImages<\/code> kullanarak \u00f6nceki duruma eri\u015fmek \u00f6nemlidir).<br \/>\n    *   <code>setPage<\/code> ile sayfa numaras\u0131n\u0131 bir art\u0131r\u0131r.<br \/>\n    *   Belirli bir sayfa say\u0131s\u0131na ula\u015f\u0131ld\u0131\u011f\u0131nda veya API&#8217;den bo\u015f veri geldi\u011finde <code>setHasMore(false)<\/code> ile daha fazla resim olmad\u0131\u011f\u0131n\u0131 belirtir.<br \/>\n    *   <code>finally<\/code> blo\u011funda <code>setLoading(false)<\/code> ile y\u00fckleme durumunu sonland\u0131r\u0131r.<br \/>\n*   <strong>\u0130lk <code>useEffect<\/code> (Bo\u015f Ba\u011f\u0131ml\u0131l\u0131k Dizisi):<\/strong><br \/>\n    *   Bile\u015fen ilk kez render edildi\u011finde <code>fetchImages<\/code> fonksiyonunu \u00e7a\u011f\u0131rarak ilk resim grubunu y\u00fckler.<br \/>\n*   <strong>\u0130kinci <code>useEffect<\/code> (Kayd\u0131rma Olay\u0131 Dinleyicisi):<\/strong><br \/>\n    *   <code>window.addEventListener('scroll', handleScroll)<\/code> ile pencere kayd\u0131rma olay\u0131n\u0131 dinler.<br \/>\n    *   <code>handleScroll<\/code> fonksiyonu, <code>document.documentElement.scrollTop<\/code>, <code>clientHeight<\/code> ve <code>scrollHeight<\/code> de\u011ferlerini kullanarak kullan\u0131c\u0131n\u0131n sayfan\u0131n alt\u0131na ne kadar yakla\u015ft\u0131\u011f\u0131n\u0131 hesaplar.<br \/>\n    <em>   Kullan\u0131c\u0131 sayfan\u0131n %80&#8217;ine ula\u015ft\u0131\u011f\u0131nda (<code>scrollTop + clientHeight >= scrollHeight <\/em> 0.8<\/code>), <code>loading<\/code> durumu <code>false<\/code> ise ve <code>hasMore<\/code> durumu <code>true<\/code> ise <code>fetchImages<\/code> fonksiyonunu \u00e7a\u011f\u0131rarak yeni resimler y\u00fckler.<br \/>\n    *   <code>return () => window.removeEventListener('scroll', handleScroll);<\/code> sat\u0131r\u0131, bile\u015fen DOM&#8217;dan kald\u0131r\u0131ld\u0131\u011f\u0131nda bellek s\u0131z\u0131nt\u0131lar\u0131n\u0131 \u00f6nlemek i\u00e7in olay dinleyicisini temizler. Bu, <code>useEffect<\/code> kancas\u0131n\u0131n temizleme mekanizmas\u0131d\u0131r.<\/p>\n<p>### Bile\u015fenlerin Olu\u015fturulmas\u0131: <code>ImageCard<\/code> ve <code>GalleryGrid<\/code><\/p>\n<p>\u015eimdi \u00e7ekilen resimleri g\u00f6stermek i\u00e7in <code>ImageCard<\/code> ve <code>GalleryGrid<\/code> bile\u015fenlerini olu\u015ftural\u0131m.<\/p>\n<p>#### <code>ImageCard.jsx<\/code><\/p>\n<p>Bu bile\u015fen, tek bir resmi ve ilgili bilgilerini (varsa) g\u00f6stermekten sorumludur.<\/p>\n<pre><code class=\"language-jsx\">\/\/ src\/components\/ImageCard.jsx\nimport React from 'react';\nimport '.\/ImageCard.css'; \/\/ ImageCard i\u00e7in \u00f6zel CSS\n\nconst ImageCard = ({ image }) => {\n  return (\n    <div className=\"image-card\">\n      <img src={image.src} alt={image.alt} loading=\"lazy\" \/>\n      {\/<em> \u0130ste\u011fe ba\u011fl\u0131 olarak resim ba\u015fl\u0131\u011f\u0131, yazar bilgisi eklenebilir <\/em>\/}\n      {\/<em> <p className=\"image-alt\">{image.alt}<\/p> <\/em>\/}\n    <\/div>\n  );\n};\n\nexport default ImageCard;<\/code><\/pre>\n<p><strong><code>ImageCard.css<\/code>:<\/strong><\/p>\n<pre><code class=\"language-css\">\/<em> src\/components\/ImageCard.css <\/em>\/\n.image-card {\n  background-color: #f0f0f0;\n  border-radius: 8px;\n  overflow: hidden;\n  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n  display: flex;\n  flex-direction: column;\n  height: 100%; \/<em> Grid \u00f6\u011felerinin e\u015fit y\u00fcksekli\u011fe sahip olmas\u0131n\u0131 sa\u011flar <\/em>\/\n}\n\n.image-card img {\n  width: 100%;\n  height: 200px; \/<em> Sabit bir y\u00fckseklik veya aspect-ratio kullanabilirsiniz <\/em>\/\n  object-fit: cover; \/<em> Resmi kutuya s\u0131\u011fd\u0131r\u0131r, oran\u0131n\u0131 korur <\/em>\/\n  display: block;\n}\n\n.image-card .image-alt {\n  padding: 10px;\n  font-size: 0.9em;\n  color: #555;\n}<\/code><\/pre>\n<p><strong>Kod A\u00e7\u0131klamas\u0131:<\/strong><\/p>\n<p>*   <code>ImageCard<\/code> bile\u015feni, <code>image<\/code> ad\u0131nda bir prop al\u0131r. Bu prop, resmin <code>src<\/code> (kaynak URL) ve <code>alt<\/code> (alternatif metin) gibi bilgilerini i\u00e7eren bir nesnedir.<br \/>\n*   <code><img><\/code> etiketi, <code>src<\/code> ve <code>alt<\/code> \u00f6zelliklerini kullanarak resmi g\u00f6r\u00fcnt\u00fcler.<br \/>\n*   <code>loading=\"lazy\"<\/code> \u00f6zelli\u011fi, resimlerin g\u00f6r\u00fcn\u00fcr alana (viewport) yak\u0131n olana kadar y\u00fcklenmesini geciktirerek performans\u0131 art\u0131r\u0131r. Bu, \u00f6zellikle sonsuz kayd\u0131rmal\u0131 galerilerde \u00e7ok say\u0131da resim oldu\u011funda \u00f6nemlidir.<br \/>\n*   CSS, her bir resim kart\u0131n\u0131n ho\u015f bir g\u00f6r\u00fcn\u00fcme sahip olmas\u0131n\u0131 sa\u011flar. <code>object-fit: cover;<\/code> resmi k\u0131rparak belirlenen alana s\u0131\u011fd\u0131r\u0131r ve oran\u0131n\u0131 korur.<\/p>\n<p>#### <code>GalleryGrid.jsx<\/code><\/p>\n<p>Bu bile\u015fen, \u00e7ekilen t\u00fcm <code>ImageCard<\/code> bile\u015fenlerini bir CSS Grid d\u00fczeninde d\u00fczenler.<\/p>\n<pre><code class=\"language-jsx\">\/\/ src\/components\/GalleryGrid.jsx\nimport React from 'react';\nimport ImageCard from '.\/ImageCard';\nimport '.\/GalleryGrid.css'; \/\/ GalleryGrid i\u00e7in \u00f6zel CSS\n\nconst GalleryGrid = ({ images }) => {\n  return (\n    <div className=\"gallery-grid\">\n      {images.map(image => (\n        <ImageCard key={image.id} image={image} \/>\n      ))}\n    <\/div>\n  );\n};\n\nexport default GalleryGrid;<\/code><\/pre>\n<p><strong><code>GalleryGrid.css<\/code>:<\/strong><\/p>\n<pre><code class=\"language-css\">\/<em> src\/components\/GalleryGrid.css <\/em>\/\n.gallery-grid {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); \/<em> Duyarl\u0131 \u0131zgara <\/em>\/\n  gap: 20px; \/<em> Izgara \u00f6\u011feleri aras\u0131ndaki bo\u015fluk <\/em>\/\n  padding: 20px;\n  max-width: 1200px; \/<em> Maksimum geni\u015flik <\/em>\/\n  margin: 0 auto; \/<em> Ortala <\/em>\/\n}\n\n\/<em> K\u00fc\u00e7\u00fck ekranlar i\u00e7in medya sorgusu <\/em>\/\n@media (max-width: 768px) {\n  .gallery-grid {\n    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n    gap: 15px;\n    padding: 15px;\n  }\n}\n\n@media (max-width: 480px) {\n  .gallery-grid {\n    grid-template-columns: 1fr; \/<em> Tek s\u00fctun <\/em>\/\n    gap: 10px;\n    padding: 10px;\n  }\n}<\/code><\/pre>\n<p><strong>Kod A\u00e7\u0131klamas\u0131:<\/strong><\/p>\n<p>*   <code>GalleryGrid<\/code> bile\u015feni, <code>images<\/code> ad\u0131nda bir dizi prop al\u0131r.<br \/>\n*   <code>images.map()<\/code> fonksiyonu kullan\u0131larak dizideki her bir resim nesnesi i\u00e7in bir <code>ImageCard<\/code> bile\u015feni olu\u015fturulur.<br \/>\n*   <code>key<\/code> prop&#8217;u, React&#8217;in liste \u00f6\u011felerini verimli bir \u015fekilde g\u00fcncellemesi i\u00e7in benzersiz bir de\u011fer olmal\u0131d\u0131r (burada <code>image.id<\/code> kullan\u0131ld\u0131).<br \/>\n*   CSS Grid \u00f6zellikleri <code>gallery-grid<\/code> s\u0131n\u0131f\u0131na uygulan\u0131r:<br \/>\n    *   <code>display: grid;<\/code>: \u00d6\u011felerin bir \u0131zgara d\u00fczeninde yerle\u015ftirilmesini sa\u011flar.<br \/>\n    *   <code>grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));<\/code>: Bu, en \u00f6nemli k\u0131s\u0131md\u0131r.<br \/>\n        *   <code>repeat()<\/code>: Belirtilen deseni tekrarlar.<br \/>\n        *   <code>auto-fill<\/code>: Mevcut alana s\u0131\u011fabilecek kadar s\u00fctun olu\u015fturur.<br \/>\n        *   <code>minmax(280px, 1fr)<\/code>: Her s\u00fctunun minimum geni\u015fli\u011fi 280 piksel, maksimum geni\u015fli\u011fi ise kullan\u0131labilir alan\u0131n bir fraksiyonu (1fr) kadar olmas\u0131n\u0131 sa\u011flar. Bu sayede \u0131zgara, ekran boyutuna g\u00f6re otomatik olarak s\u00fctun say\u0131s\u0131n\u0131 ayarlar ve duyarl\u0131 bir yap\u0131 kazan\u0131r.<br \/>\n    *   <code>gap: 20px;<\/code>: Izgara \u00f6\u011feleri aras\u0131nda 20 piksel bo\u015fluk b\u0131rak\u0131r.<br \/>\n    *   Medya sorgular\u0131 (<code>@media<\/code>) kullan\u0131larak farkl\u0131 ekran boyutlar\u0131 i\u00e7in \u0131zgara d\u00fczeni optimize edilir. \u00d6zellikle mobil cihazlarda tek s\u00fctunlu bir d\u00fczen tercih edilebilir.<\/p>\n<p>### Global CSS Dosyas\u0131<\/p>\n<p>Uygulamam\u0131z\u0131n genel g\u00f6r\u00fcn\u00fcm\u00fcn\u00fc ayarlamak i\u00e7in <code>App.css<\/code> dosyam\u0131z\u0131 g\u00fcncelleyelim (veya <code>index.css<\/code> kullanabiliriz).<\/p>\n<pre><code class=\"language-css\">\/<em> src\/App.css veya src\/index.css <\/em>\/\nbody {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n    sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  background-color: #f8f8f8;\n  color: #333;\n}\n\n.App {\n  text-align: center;\n  padding-bottom: 50px; \/<em> Y\u00fckleme g\u00f6stergesi i\u00e7in alt bo\u015fluk <\/em>\/\n}\n\nh1 {\n  color: #2c3e50;\n  margin-top: 30px;\n  margin-bottom: 30px;\n}\n\n.loading-indicator,\n.no-more-images,\n.no-images-found {\n  margin: 20px auto;\n  padding: 10px 20px;\n  background-color: #e0f7fa;\n  color: #00796b;\n  border-radius: 5px;\n  max-width: 300px;\n  font-weight: bold;\n}\n\n.no-more-images {\n  background-color: #fff3e0;\n  color: #e65100;\n}\n\n.no-images-found {\n  background-color: #ffebee;\n  color: #c62828;\n}<\/code><\/pre>\n<p>Bu CSS, uygulaman\u0131n genel font ayarlar\u0131n\u0131, arka plan rengini ve y\u00fckleme\/mesaj g\u00f6stergelerinin stilini belirler.<\/p>\n<p>### Performans ve Kullan\u0131c\u0131 Deneyimi \u0130yile\u015ftirmeleri<\/p>\n<p>Sonsuz kayd\u0131rmal\u0131 galerilerde performans ve kullan\u0131c\u0131 deneyimi kritik \u00f6neme sahiptir. \u0130\u015fte uygulaman\u0131z\u0131 daha iyi hale getirecek baz\u0131 ek ipu\u00e7lar\u0131:<\/p>\n<h4>Debounce veya Throttle Kullan\u0131m\u0131<\/h4>\n<p>Kayd\u0131rma olaylar\u0131 \u00e7ok s\u0131k tetiklenir ve bu da <code>handleScroll<\/code> fonksiyonunun gere\u011finden fazla \u00e7al\u0131\u015fmas\u0131na neden olabilir. Bu durumu \u00f6nlemek i\u00e7in <code>debounce<\/code> veya <code>throttle<\/code> tekniklerini kullanmak faydal\u0131d\u0131r.<\/p>\n<p>*   <strong>Debounce:<\/strong> Bir olay tetiklendi\u011finde, belirli bir s\u00fcre i\u00e7inde ba\u015fka bir tetikleme olmazsa fonksiyonu \u00e7al\u0131\u015ft\u0131r\u0131r. \u00d6rne\u011fin, kullan\u0131c\u0131 kayd\u0131rmay\u0131 durdurduktan 200ms sonra fonksiyon \u00e7al\u0131\u015f\u0131r.<br \/>\n*   <strong>Throttle:<\/strong> Bir olay tetiklendi\u011finde, belirli bir zaman aral\u0131\u011f\u0131nda fonksiyonun yaln\u0131zca bir kez \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flar. \u00d6rne\u011fin, her 200ms&#8217;de bir fonksiyon \u00e7al\u0131\u015f\u0131r, daha s\u0131k tetiklenmez.<\/p>\n<p>Bu \u00f6rnekte, <code>handleScroll<\/code> i\u00e7indeki kontrol (<code>!loading && hasMore<\/code>) zaten gereksiz <code>fetchImages<\/code> \u00e7a\u011fr\u0131lar\u0131n\u0131 engelledi\u011fi i\u00e7in basit bir uygulama i\u00e7in yeterli olabilir. Ancak \u00e7ok karma\u015f\u0131k hesaplamalar yapan bir <code>handleScroll<\/code> fonksiyonunuz varsa, bir <code>debounce<\/code> yard\u0131mc\u0131 fonksiyonu eklemek iyi bir fikir olabilir.<\/p>\n<pre><code class=\"language-javascript\">\/\/ Debounce yard\u0131mc\u0131 fonksiyonu \u00f6rne\u011fi\nconst debounce = (func, delay) => {\n  let timeout;\n  return function(...args) {\n    const context = this;\n    clearTimeout(timeout);\n    timeout = setTimeout(() => func.apply(context, args), delay);\n  };\n};\n\n\/\/ useEffect i\u00e7inde kullan\u0131m\u0131\nuseEffect(() => {\n  const debouncedHandleScroll = debounce(handleScroll, 200); \/\/ 200ms debounce\n  window.addEventListener('scroll', debouncedHandleScroll);\n  return () => window.removeEventListener('scroll', debouncedHandleScroll);\n}, [loading, hasMore, fetchImages]);<\/code><\/pre>\n<h4>Resim Optimizasyonu ve Lazy Loading<\/h4>\n<p>*   <strong><code>loading=\"lazy\"<\/code>:<\/strong> Daha \u00f6nce <code>ImageCard<\/code> bile\u015feninde kulland\u0131\u011f\u0131m\u0131z <code>loading=\"lazy\"<\/code> \u00f6zelli\u011fi, taray\u0131c\u0131n\u0131n resimleri sadece g\u00f6r\u00fcn\u00fcr alana (viewport) yak\u0131n olduklar\u0131nda y\u00fcklemesini sa\u011flar. Bu, ba\u015flang\u0131\u00e7 y\u00fckleme s\u00fcresini \u00f6nemli \u00f6l\u00e7\u00fcde azalt\u0131r.<br \/>\n*   <strong>Duyarl\u0131 Resimler (<code>srcset<\/code>):<\/strong> Farkl\u0131 ekran boyutlar\u0131 ve \u00e7\u00f6z\u00fcn\u00fcrl\u00fckler i\u00e7in uygun boyutlarda resimler sunmak, bant geni\u015fli\u011finden tasarruf sa\u011flar ve y\u00fckleme h\u0131z\u0131n\u0131 art\u0131r\u0131r. <code><img decoding=\"async\" src=\"...\" srcset=\"small.jpg 480w, medium.jpg 800w, large.jpg 1200w\" sizes=\"(max-width: 600px) 480px, (max-width: 1000px) 800px, 1200px\" alt=\"...\" \/><\/code> yap\u0131s\u0131 kullan\u0131labilir.<br \/>\n*   <strong>Resim S\u0131k\u0131\u015ft\u0131rma:<\/strong> Sunucu taraf\u0131nda resimleri optimize edilmi\u015f formatlarda (WebP gibi) ve uygun s\u0131k\u0131\u015ft\u0131rma oranlar\u0131nda sunmak, dosya boyutlar\u0131n\u0131 k\u00fc\u00e7\u00fclt\u00fcr.<\/p>\n<h4>Kullan\u0131c\u0131 Geri Bildirimi<\/h4>\n<p>*   <strong>Y\u00fckleme G\u00f6stergeleri:<\/strong> <code>loading<\/code> durumu <code>true<\/code> oldu\u011funda bir spinner veya &#8220;Y\u00fckleniyor&#8230;&#8221; mesaj\u0131 g\u00f6stermek, kullan\u0131c\u0131n\u0131n uygulaman\u0131n \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 anlamas\u0131n\u0131 sa\u011flar.<br \/>\n*   <strong>&#8220;Daha Fazla Resim Yok&#8221; Mesaj\u0131:<\/strong> <code>hasMore<\/code> durumu <code>false<\/code> oldu\u011funda bu mesaj\u0131 g\u00f6stermek, kullan\u0131c\u0131n\u0131n daha fazla i\u00e7erik beklememesini sa\u011flar.<br \/>\n*   <strong>Hata Mesajlar\u0131:<\/strong> API \u00e7a\u011fr\u0131s\u0131 s\u0131ras\u0131nda bir hata olu\u015ftu\u011funda kullan\u0131c\u0131ya bilgilendirici bir mesaj g\u00f6stermek, uygulaman\u0131n sa\u011flaml\u0131\u011f\u0131n\u0131 art\u0131r\u0131r.<\/p>\n<h4>Eri\u015filebilirlik (Accessibility &#8211; A11y)<\/h4>\n<p>*   <strong><code>alt<\/code> Nitelikleri:<\/strong> T\u00fcm <code><img><\/code> etiketlerinde a\u00e7\u0131klay\u0131c\u0131 <code>alt<\/code> nitelikleri kullanmak, ekran okuyucular kullanan g\u00f6rme engelli kullan\u0131c\u0131lar i\u00e7in \u00f6nemlidir. Bu, ayn\u0131 zamanda SEO i\u00e7in de faydal\u0131d\u0131r.<br \/>\n*   <strong>Klavye Navigasyonu:<\/strong> Galeri \u00f6\u011felerinin klavye ile gezilebilir olmas\u0131n\u0131 sa\u011flamak (tab index vb. kullanarak), fare kullanamayan kullan\u0131c\u0131lar i\u00e7in \u00f6nemlidir.<\/p>\n<h4>Sanalla\u015ft\u0131rma (Virtualization)<\/h4>\n<p>\u00c7ok b\u00fcy\u00fck galerilerde (binlerce resim), DOM&#8217;da \u00e7ok say\u0131da \u00f6\u011fe bulundurmak performans\u0131 ciddi \u015fekilde etkileyebilir. Sanalla\u015ft\u0131rma (veya pencereleme &#8211; windowing), sadece g\u00f6r\u00fcn\u00fcr alandaki (veya g\u00f6r\u00fcn\u00fcr alana yak\u0131n) \u00f6\u011feleri render ederek bu sorunu \u00e7\u00f6zer. React-Window veya React-Virtualize gibi k\u00fct\u00fcphaneler bu ama\u00e7la kullan\u0131labilir. Ancak bu, daha karma\u015f\u0131k bir konudur ve bu makalenin kapsam\u0131n\u0131n d\u0131\u015f\u0131ndad\u0131r, ancak \u00e7ok b\u00fcy\u00fck veri setleri i\u00e7in ak\u0131lda tutulmas\u0131 gereken bir \u00e7\u00f6z\u00fcmd\u00fcr.<\/p>\n<p>### Sonu\u00e7<\/p>\n<p>Bu makalede, React ve CSS Grid kullanarak nas\u0131l duyarl\u0131 ve sonsuz kayd\u0131rmal\u0131 bir resim galerisi olu\u015fturulaca\u011f\u0131n\u0131 ad\u0131m ad\u0131m \u00f6\u011frendik. React&#8217;in durum y\u00f6netimi (<code>useState<\/code>) ve ya\u015fam d\u00f6ng\u00fcs\u00fc (<code>useEffect<\/code>) kancalar\u0131n\u0131 kullanarak dinamik veri \u00e7ekme ve kayd\u0131rma olaylar\u0131n\u0131 yakalama mekanizmas\u0131n\u0131 kurduk. CSS Grid&#8217;in g\u00fc\u00e7l\u00fc <code>grid-template-columns<\/code> \u00f6zelli\u011fi sayesinde, farkl\u0131 ekran boyutlar\u0131na uyum sa\u011flayan esnek ve otomatik bir \u0131zgara d\u00fczeni olu\u015fturduk.<\/p>\n<p>Uygulamam\u0131z\u0131n temel ta\u015flar\u0131 \u015funlard\u0131:<br \/>\n*   <code>App.jsx<\/code>: Ana uygulama bile\u015feni, durum y\u00f6netimi, API \u00e7a\u011fr\u0131s\u0131 sim\u00fclasyonu ve kayd\u0131rma olay\u0131n\u0131 dinleme.<br \/>\n*   <code>GalleryGrid.jsx<\/code>: Resim kartlar\u0131n\u0131 CSS Grid d\u00fczeninde d\u00fczenleyen kapsay\u0131c\u0131 bile\u015fen.<br \/>\n*   <code>ImageCard.jsx<\/code>: Tek bir resmi g\u00f6steren ve lazy loading \u00f6zelli\u011fini kullanan bile\u015fen.<\/p>\n<p>Ayr\u0131ca, performans, kullan\u0131c\u0131 deneyimi ve eri\u015filebilirlik gibi \u00f6nemli konulara de\u011finerek, uygulaman\u0131z\u0131 daha sa\u011flam ve kullan\u0131c\u0131 dostu hale getirecek iyile\u015ftirmelerden bahsettik. Debounce\/throttle, resim optimizasyonu ve kullan\u0131c\u0131 geri bildirimi, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmezleridir.<\/p>\n<p>Bu rehber, sonsuz kayd\u0131rmal\u0131 galeriler olu\u015fturmak i\u00e7in sa\u011flam bir temel sunmaktad\u0131r. Ger\u00e7ek projelerde, mock API yerine ger\u00e7ek bir resim API&#8217;si (Unsplash, Pexels vb.) entegre edebilir, hata y\u00f6netimi ve kullan\u0131c\u0131 aray\u00fcz\u00fc geri bildirimlerini daha detayl\u0131 hale getirebilirsiniz. React ve CSS Grid&#8217;in birle\u015fimi, bu t\u00fcr dinamik ve g\u00f6rsel a\u00e7\u0131dan zengin uygulamalar\u0131 geli\u015ftirirken size b\u00fcy\u00fck esneklik ve g\u00fc\u00e7 sa\u011flayacakt\u0131r. Art\u0131k kendi sonsuz kayd\u0131rma galerilerinizi olu\u015fturmak i\u00e7in gerekli bilgi ve ara\u00e7lara sahipsiniz!<\/body><\/p>\n","protected":false},"excerpt":{"rendered":"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?\nWeb uygulamalar\u0131nda kullan\u0131c\u0131 deneyimini zenginle\u015ftiren ve veri","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[128],"tags":[],"class_list":{"0":"post-34387","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-react","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?\" \/>\n<meta property=\"og:description\" content=\"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur? Web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimini zenginle\u015ftiren ve veri\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-11-15T23:40:41+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"15 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?\",\"datePublished\":\"2025-11-15T23:40:41+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/\"},\"wordCount\":2244,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"React\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/\",\"name\":\"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-11-15T23:40:41+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/","og_locale":"tr_TR","og_type":"article","og_title":"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?","og_description":"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur? Web uygulamalar\u0131nda kullan\u0131c\u0131 deneyimini zenginle\u015ftiren ve veri","og_url":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-11-15T23:40:41+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"15 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?","datePublished":"2025-11-15T23:40:41+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/"},"wordCount":2244,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["React"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/","url":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/","name":"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-11-15T23:40:41+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/react-ve-css-grid-ile-sonsuz-kaydirmali-bir-resim-galerisi-nasil-olusturulur\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"React ve CSS Grid ile Sonsuz Kayd\u0131rmal\u0131 Bir Resim Galerisi Nas\u0131l Olu\u015fturulur?"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34387","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=34387"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34387\/revisions"}],"predecessor-version":[{"id":34388,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34387\/revisions\/34388"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=34387"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=34387"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=34387"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}