React'te Sonsuz Kaydırma ve Görüntü Tembel Yükleme Uygulaması
Yayınlanan: 2022-03-10HTML
Intersection Observer
API'sinin nasıl kullanılacağını öğreneceğiz. Bu süreçte, React'in bazı kancalarının nasıl kullanılacağını ve Özel Kancaların nasıl oluşturulacağını öğreneceğiz.Sayfalandırmaya bir alternatif arıyorsanız, sonsuz kaydırma iyi bir fikirdir. Bu makalede, bir React işlevsel bileşeni bağlamında Intersection Observer API için bazı kullanım örneklerini keşfedeceğiz. Okuyucu, React fonksiyonel bileşenleri hakkında çalışan bir bilgiye sahip olmalıdır. Birkaçına göz atacağımız için, React kancalarına biraz aşina olmak faydalı olacaktır, ancak gerekli değildir.
Amacımız, bu makalenin sonunda, yerel bir HTML API kullanarak sonsuz kaydırma ve görüntü tembel yüklemeyi gerçekleştirmiş olmamızdır. Ayrıca React Hooks hakkında birkaç şey daha öğrenmiş olurduk. Bununla, gerektiğinde React uygulamanızda sonsuz kaydırma ve görüntü tembel yükleme uygulayabilirsiniz.
Başlayalım.
React ve Leaflet ile Harita Oluşturma
Bir CSV veya JSON dosyasından bilgi almak sadece karmaşık değil, aynı zamanda sıkıcıdır. Aynı verileri görsel yardım şeklinde temsil etmek daha basittir. Shajia Abidi, Leaflet'in ne kadar güçlü bir araç olduğunu ve birçok farklı türde haritanın nasıl oluşturulabileceğini açıklıyor. İlgili bir makaleyi okuyun →
Kavşak Gözlemci API'sı
MDN belgelerine göre, “Kesişim Gözlemcisi API'si, bir hedef öğenin bir üst öğeyle veya bir üst düzey belgenin görünüm alanıyla kesişimindeki değişiklikleri eşzamansız olarak gözlemlemek için bir yol sağlar”.
Bu API, sonsuz kaydırma ve görüntü gecikmeli yükleme gibi harika özellikleri uygulamamıza olanak tanır. Kavşak gözlemcisi, yapıcısını çağırarak ve ona bir geri arama ve bir seçenekler nesnesi ileterek oluşturulur. target
adı verilen bir öğe, aygıt görünüm alanıyla veya root
adı verilen belirli bir öğeyle kesiştiğinde geri arama çağrılır. Seçenekler argümanında özel bir kök belirtebilir veya varsayılan değeri kullanabiliriz.
let observer = new IntersectionObserver(callback, options);
API'nin kullanımı basittir. Tipik bir örnek şöyle görünür:
var intObserver = new IntersectionObserver(entries => { entries.forEach(entry => { console.log(entry) console.log(entry.isIntersecting) // returns true if the target intersects the root element }) }, { // default options } ); let target = document.querySelector('#targetId'); intObserver.observe(target); // start observation
entries
, IntersectionObserverEntry
nesnelerinin bir listesidir. IntersectionObserverEntry
nesnesi, gözlemlenen bir hedef öğe için bir kesişim değişikliğini tanımlar. Geri aramanın, ana iş parçacığında çalıştığı için zaman alan herhangi bir görevi yerine getirmemesi gerektiğini unutmayın.
Intersection Observer API, caniuse'da gösterildiği gibi şu anda geniş tarayıcı desteğine sahiptir.
API hakkında daha fazla bilgiyi kaynaklar bölümünde sağlanan bağlantılardan okuyabilirsiniz.
Şimdi bu API'yi gerçek bir React uygulamasında nasıl kullanabileceğimize bakalım. Uygulamamızın son versiyonu, sonsuz kaydırılan ve her bir resmin tembelce yüklendiği bir resim sayfası olacaktır.
useEffect
Hook ile API Çağrıları Yapma
Başlamak için başlangıç projesini bu URL'den kopyalayın. Minimum kurulum ve tanımlanmış birkaç stile sahiptir. Ayrıca, sınıflarını stil için kullanacağım için public/index.html
dosyasına Bootstrap
bir bağlantı ekledim.
İsterseniz yeni bir proje oluşturmaktan çekinmeyin. Repo ile takip etmek istiyorsanız yarn
paket yöneticisinin kurulu olduğundan emin olun. Özel işletim sisteminiz için kurulum talimatlarını burada bulabilirsiniz.
Bu eğitim için, genel bir API'den resimler alıp sayfada görüntüleyeceğiz. Lorem Picsum API'lerini kullanacağız.
Bu eğitim için, bir dizi resim nesnesi döndüren https://picsum.photos/v2/list?page=0&limit=10
bitiş noktasını kullanacağız. Sonraki on resmi almak için sayfanın değerini 1, ardından 2 vb. olarak değiştiririz.
Şimdi Uygulama bileşenini parça parça oluşturacağız.
src/App.js
açın ve aşağıdaki kodu girin.
import React, { useEffect, useReducer } from 'react'; import './index.css'; function App() { const imgReducer = (state, action) => { switch (action.type) { case 'STACK_IMAGES': return { ...state, images: state.images.concat(action.images) } case 'FETCHING_IMAGES': return { ...state, fetching: action.fetching } default: return state; } } const [imgData, imgDispatch] = useReducer(imgReducer,{ images:[], fetching: true}) // next code block goes here }
İlk olarak, bir redüktör işlevi tanımlıyoruz, imgReducer
. Bu redüktör iki eylemi gerçekleştirir.
-
STACK_IMAGES
eylemi,images
dizisini birleştirir. -
FETCHING_IMAGES
eylemi,fetching
değişkeninin değerinitrue
vefalse
arasında değiştirir.
Bir sonraki adım, bu redüktörü bir useReducer
kancasına bağlamaktır. Bu yapıldıktan sonra, iki şeyi geri alırız:
-
imgData
, iki değişken içerir:images
, resim nesneleri dizisidir.fetching
, API çağrısının devam edip etmediğini bize söyleyen bir booledir. - redüktör nesnesini güncellemek için bir işlev olan
imgDispatch
.
React belgelerinde useReducer
kancası hakkında daha fazla bilgi edinebilirsiniz.
Kodun sonraki kısmı, API çağrısını yaptığımız yerdir. Aşağıdaki kodu App.js
önceki kod bloğunun altına yapıştırın.
// make API calls useEffect(() => { imgDispatch({ type: 'FETCHING_IMAGES', fetching: true }) fetch('https://picsum.photos/v2/list?page=0&limit=10') .then(data => data.json()) .then(images => { imgDispatch({ type: 'STACK_IMAGES', images }) imgDispatch({ type: 'FETCHING_IMAGES', fetching: false }) }) .catch(e => { // handle error imgDispatch({ type: 'FETCHING_IMAGES', fetching: false }) return e }) }, [ imgDispatch ]) // next code block goes here
useEffect
kancasının içinde, fetch
API'si ile API uç noktasına bir çağrı yaparız. Ardından, STACK_IMAGES
eylemini göndererek, API çağrısının sonucuyla görüntüler dizisini güncelleriz. API çağrısı tamamlandıktan sonra FETCHING_IMAGES
eylemini de göndeririz.
Sonraki kod bloğu, işlevin dönüş değerini tanımlar. useEffect
kancasından sonra aşağıdaki kodu girin.
return ( <div className=""> <nav className="navbar bg-light"> <div className="container"> <a className="navbar-brand" href="/#"> <h2>Infinite scroll + image lazy loading</h2> </a> </div> </navv <div id='images' className="container"> <div className="row"> {imgData.images.map((image, index) => { const { author, download_url } = image return ( <div key={index} className="card"> <div className="card-body "> <img alt={author} className="card-img-top" src={download_url} /> </div> <div className="card-footer"> <p className="card-text text-center text-capitalize text-primary">Shot by: {author}</p> </div> </div> ) })} </div> </div> </div> );
Görüntüleri görüntülemek için, imgData
nesnesindeki görüntüler dizisi üzerinde eşleniriz.
Şimdi uygulamayı başlatın ve sayfayı tarayıcıda görüntüleyin. Duyarlı bir ızgarada güzel bir şekilde görüntülenen görüntüleri görmelisiniz.
Son bit, Uygulama bileşenini dışa aktarmaktır.
export default App;
Bu noktada karşılık gelen dal 01-make-api-calls'dır.
Şimdi sayfa kaydırılırken daha fazla resim görüntüleyerek bunu genişletelim.
Sonsuz Kaydırma Uygulaması
Sayfa ilerledikçe daha fazla resim sunmayı amaçlıyoruz. API uç noktasının URL'sinden, https://picsum.photos/v2/list?page=0&limit=10
, yeni bir fotoğraf grubu elde etmek için yalnızca page
değerini artırmamız gerektiğini biliyoruz. Gösterecek resimlerimiz bittiğinde de bunu yapmamız gerekiyor. Buradaki amacımız için sayfanın en altına geldiğimizde resimlerin bittiğini anlayacağız. Intersection Observer API'sinin bunu başarmamıza nasıl yardımcı olduğunu görmenin zamanı geldi.
src/App.js
açın ve imgReducer altında yeni bir redüktör, pageReducer
imgReducer
.
// App.js const imgReducer = (state, action) => { ... } const pageReducer = (state, action) => { switch (action.type) { case 'ADVANCE_PAGE': return { ...state, page: state.page + 1 } default: return state; } } const [ pager, pagerDispatch ] = useReducer(pageReducer, { page: 0 })
Sadece bir eylem tipi tanımlıyoruz. ADVANCE_PAGE
eylemi her tetiklendiğinde, page
değeri 1 artırılır.
Aşağıda gösterildiği gibi sayfa numaralarını dinamik olarak kabul etmek için fetch
işlevindeki URL'yi güncelleyin.
fetch(`https://picsum.photos/v2/list?page=${pager.page}&limit=10`)
pager.page
ile birlikte bağımlılık dizisine imgData
. Bunu yapmak, pager.page
her değiştiğinde API çağrısının çalışmasını sağlar.
useEffect(() => { ... }, [ imgDispatch, pager.page ])
API çağrısı için useEffect
kancasından sonra aşağıdaki kodu girin. İçe aktarma satırınızı da güncelleyin.
// App.js import React, { useEffect, useReducer, useCallback, useRef } from 'react'; useEffect(() => { ... }, [ imgDispatch, pager.page ]) // implement infinite scrolling with intersection observer let bottomBoundaryRef = useRef(null); const scrollObserver = useCallback( node => { new IntersectionObserver(entries => { entries.forEach(en => { if (en.intersectionRatio > 0) { pagerDispatch({ type: 'ADVANCE_PAGE' }); } }); }).observe(node); }, [pagerDispatch] ); useEffect(() => { if (bottomBoundaryRef.current) { scrollObserver(bottomBoundaryRef.current); } }, [scrollObserver, bottomBoundaryRef]);
Bir bottomBoundaryRef
değişkeni tanımlıyoruz ve değerini useRef(null)
olarak ayarlıyoruz. useRef
, değişkenlerin bileşen oluşturma işlemleri boyunca değerlerini korumasına izin verir, yani, içeren bileşen yeniden oluşturulduğunda değişkenin geçerli değeri devam eder. Değerini değiştirmenin tek yolu, o değişkene .current
özelliğini yeniden atamaktır.
Bizim durumumuzda, bottomBoundaryRef.current
değeri null
ile başlar. Sayfa oluşturma döngüsü ilerledikçe, mevcut özelliğini <div id='page-bottom-boundary'>
düğümü olarak ayarladık.
React'e bu atamanın bildirildiği div olarak bottomBoundaryRef.current
ayarlamasını söylemek için ref={bottomBoundaryRef}
atama ifadesini kullanırız.
Böylece,
bottomBoundaryRef.current = null
işleme döngüsünün sonunda şu hale gelir:
bottomBoundaryRef.current = <div></div>
Bu atamanın nerede yapıldığını birazdan göreceğiz.
Ardından, gözlemcinin ayarlanacağı bir scrollObserver
işlevi tanımlarız. Bu işlev, gözlemlenecek bir DOM
düğümünü kabul eder. Burada dikkat edilmesi gereken en önemli nokta, gözlem altındaki kavşağa her geldiğimizde ADVANCE_PAGE
eylemini göndermemizdir. Efekt, pager.page
değerini 1 arttırmaktır. Bu gerçekleştiğinde, onu bir bağımlılık olarak içeren useEffect
kancası yeniden çalıştırılır. Bu yeniden çalıştırma, sırayla, yeni sayfa numarasıyla getirme çağrısını başlatır.
Etkinlik alayı böyle görünüyor.
Gözlem altındaki kesişme noktasına basın →ADVANCE_PAGE
eylemini çağırın →pager.page
değerini 1 artır → getirme çağrısı çalıştırmaları içinuseEffect
kancası →fetch
çağrısı çalıştırılıyor → döndürülen görüntüler,images
dizisine birleştirilir.
Bir useEffect
kancasında scrollObserver
, böylece işlev yalnızca kancanın bağımlılıklarından herhangi biri değiştiğinde çalışır. Bir useEffect
kancasının içindeki işlevi çağırmasaydık, işlev her sayfa oluşturma işleminde çalışırdı.
bottomBoundaryRef.current
<div id="page-bottom-boundary" style="border: 1px solid red;"></div>
öğesine atıfta bulunduğunu hatırlayın. scrollObserver
geçirmeden önce değerinin null olmadığını kontrol ederiz. Aksi takdirde, IntersectionObserver
yapıcısı bir hata döndürür.
Bir useEffect
kancasında scrollObserver
kullandığımız için, bitmeyen bileşen yeniden oluşturmalarını önlemek için onu bir useCallback
kancasına sarmamız gerekir. React belgelerinde useCallback hakkında daha fazla bilgi edinebilirsiniz.
<div id='images'>
div'den sonra aşağıdaki kodu girin.
// App.js <div id='image'> ... </div> {imgData.fetching && ( <div className="text-center bg-secondary m-auto p-3"> <p className="m-0 text-white">Getting images</p> </div> )} <div id='page-bottom-boundary' style={{ border: '1px solid red' }} ref={bottomBoundaryRef}></div>
API çağrısı başladığında, getirmeyi true
olarak ayarladık ve Görüntüler fetching
metni görünür hale gelir. fetching
, getirmeyi false
olarak ayarladık ve metin gizlendi. Ayrıca, yapıcı seçenekleri nesnesinde farklı bir threshold
ayarlayarak tam olarak sınıra ulaşmadan önce API çağrısını tetikleyebiliriz. Sondaki kırmızı çizgi, sayfa sınırına tam olarak ne zaman ulaştığımızı görmemizi sağlar.
Bu noktada karşılık gelen dal 02-sonsuz kaydırmadır.
Şimdi görüntü tembel yükleme uygulayacağız.
Görüntü Tembel Yüklemeyi Uygulama
Aşağı kaydırırken ağ sekmesini incelerseniz, kırmızı çizgiye (alt sınıra) basar basmaz API çağrısının gerçekleştiğini ve görüntülemeye başlamamış olsanız bile tüm resimlerin yüklenmeye başladığını görürsünüz. onlara. Bunun arzu edilen bir davranış olmamasının çeşitli nedenleri vardır. Kullanıcı bir resim görmek isteyene kadar şebeke aramalarını kaydetmek isteyebiliriz. Böyle bir durumda, görüntüleri tembelce yüklemeyi seçebiliriz, yani, görüntü kayan hale gelene kadar bir görüntü yüklemeyeceğiz.
src/App.js
açın. Sonsuz kaydırma fonksiyonlarının hemen altına aşağıdaki kodu girin.
// App.js // lazy loads images with intersection observer // only swap out the image source if the new url exists const imagesRef = useRef(null); const imgObserver = useCallback(node => { const intObs = new IntersectionObserver(entries => { entries.forEach(en => { if (en.intersectionRatio > 0) { const currentImg = en.target; const newImgSrc = currentImg.dataset.src; // only swap out the image source if the new url exists if (!newImgSrc) { console.error('Image source is invalid'); } else { currentImg.src = newImgSrc; } intObs.unobserve(node); // detach the observer when done } }); }) intObs.observe(node); }, []); useEffect(() => { imagesRef.current = document.querySelectorAll('.card-img-top'); if (imagesRef.current) { imagesRef.current.forEach(img => imgObserver(img)); } }, [imgObserver, imagesRef, imgData.images]);
scrollObserver
olduğu gibi, gözlemlenecek bir düğümü kabul eden imgObserver
adlı bir işlev tanımlarız. Sayfa, en.intersectionRatio > 0
tarafından belirlendiği gibi bir kesişmeye çarptığında, öğe üzerindeki görüntü kaynağını değiştiririz. Takas yapmadan önce yeni görüntü kaynağının var olup olmadığını kontrol ettiğimize dikkat edin. scrollObserver
işlevinde olduğu gibi, bitmeyen bileşen yeniden oluşturmayı önlemek için imgObserver'ı bir useCallback
kancasına sarıyoruz.
Ayrıca, ikame işlemini bitirdiğimizde bir img
öğesini gözlemlemeyi bıraktığımızı da unutmayın. Bunu unobserve
yöntemiyle yapıyoruz.
Aşağıdaki useEffect
kancasında, .card-img-top
sınıfına sahip tüm görüntüleri document.querySelectorAll
ile alıyoruz. Daha sonra her görüntü üzerinde yinelenir ve üzerine bir gözlemci yerleştiririz.
imgData.images
useEffect
kancasının bir bağımlılığı olarak eklediğimizi unutmayın. Bu değiştiğinde useEffect
kancasını tetikler ve sırayla her <img className='card-img-top'>
öğesiyle imgObserver
çağrılır.
<img className='card-img-top'/>
öğesini aşağıda gösterildiği gibi güncelleyin.
<img alt={author} data-src={download_url} className="card-img-top" src={'https://picsum.photos/id/870/300/300?grayscale&blur=2'} />
Her <img className='card-img-top'/>
öğesi için varsayılan bir kaynak belirledik ve göstermek istediğimiz görüntüyü data-src
özelliğinde saklıyoruz. Varsayılan resim genellikle küçük bir boyuta sahiptir, bu nedenle mümkün olduğunca az indiriyoruz. <img/>
öğesi görüntülendiğinde, data-src
özelliğindeki değer varsayılan görüntünün yerini alır.
Aşağıdaki resimde, bazı alanlarda hala gösterilen varsayılan deniz feneri görüntüsünü görüyoruz.
Bu noktada karşılık gelen dal 03 tembel yüklemedir.
Şimdi tüm bu fonksiyonları yeniden kullanılabilir hale getirmek için nasıl soyutlayacağımızı görelim.
Soyutlama Getirme, Sonsuz Kaydırma ve Özel Kancalara Tembel Yükleme
Getirme, sonsuz kaydırma ve görüntü gecikmeli yüklemeyi başarıyla uyguladık. Uygulamamızda benzer işlevselliğe ihtiyaç duyan başka bir bileşenimiz olabilir. Bu durumda, bu fonksiyonları soyutlayabilir ve yeniden kullanabiliriz. Tek yapmamız gereken onları ayrı bir dosyaya taşımak ve ihtiyacımız olan yere aktarmak. Bunları Özel Kancalara dönüştürmek istiyoruz.
React belgeleri, Özel Kancayı, adı "use"
ile başlayan ve diğer kancaları çağırabilen bir JavaScript işlevi olarak tanımlar. Bizim durumumuzda, useFetch
, useInfiniteScroll
, useLazyLoading
olmak üzere üç kanca oluşturmak istiyoruz.
src/
klasörü içinde bir dosya oluşturun. customHooks.js
olarak adlandırın ve aşağıdaki kodu içine yapıştırın.
// customHooks.js import { useEffect, useCallback, useRef } from 'react'; // make API calls and pass the returned data via dispatch export const useFetch = (data, dispatch) => { useEffect(() => { dispatch({ type: 'FETCHING_IMAGES', fetching: true }); fetch(`https://picsum.photos/v2/list?page=${data.page}&limit=10`) .then(data => data.json()) .then(images => { dispatch({ type: 'STACK_IMAGES', images }); dispatch({ type: 'FETCHING_IMAGES', fetching: false }); }) .catch(e => { dispatch({ type: 'FETCHING_IMAGES', fetching: false }); return e; }) }, [dispatch, data.page]) } // next code block here
useFetch
kancası, bir gönderme işlevini ve bir veri nesnesini kabul eder. Gönderme işlevi, API çağrısından gelen verileri App
bileşenine iletir, veri nesnesi ise API uç noktası URL'sini güncellememize izin verir.
// infinite scrolling with intersection observer export const useInfiniteScroll = (scrollRef, dispatch) => { const scrollObserver = useCallback( node => { new IntersectionObserver(entries => { entries.forEach(en => { if (en.intersectionRatio > 0) { dispatch({ type: 'ADVANCE_PAGE' }); } }); }).observe(node); }, [dispatch] ); useEffect(() => { if (scrollRef.current) { scrollObserver(scrollRef.current); } }, [scrollObserver, scrollRef]); } // next code block here
useInfiniteScroll
kancası, bir scrollRef
ve bir dispatch
işlevini kabul eder. scrollRef
, uyguladığımız bölümde daha önce tartışıldığı gibi, gözlemciyi kurmamıza yardımcı olur. Gönderme işlevi, API bitiş noktası URL'sindeki sayfa numarasını güncelleyen bir eylemi tetiklemenin bir yolunu sunar.
// lazy load images with intersection observer export const useLazyLoading = (imgSelector, items) => { const imgObserver = useCallback(node => { const intObs = new IntersectionObserver(entries => { entries.forEach(en => { if (en.intersectionRatio > 0) { const currentImg = en.target; const newImgSrc = currentImg.dataset.src; // only swap out the image source if the new url exists if (!newImgSrc) { console.error('Image source is invalid'); } else { currentImg.src = newImgSrc; } intObs.unobserve(node); // detach the observer when done } }); }) intObs.observe(node); }, []); const imagesRef = useRef(null); useEffect(() => { imagesRef.current = document.querySelectorAll(imgSelector); if (imagesRef.current) { imagesRef.current.forEach(img => imgObserver(img)); } }, [imgObserver, imagesRef, imgSelector, items]) }
useLazyLoading
kancası bir seçici ve bir dizi alır. Seçici, görüntüleri bulmak için kullanılır. Dizideki herhangi bir değişiklik, her görüntüde gözlemciyi ayarlayan useEffect
kancasını tetikler.
Yeni bir dosyaya çıkardığımızın src/App.js
sahip olduğumuz işlevlerin aynısı olduğunu görebiliriz. Şimdi iyi olan şey, argümanları dinamik olarak iletebilmemiz. Şimdi bu özel kancaları Uygulama bileşeninde kullanalım.
src/App.js
açın. Özel kancaları içe aktarın ve veri getirme, sonsuz kaydırma ve görüntü gecikmeli yükleme için tanımladığımız işlevleri silin. Redüktörleri ve useReducer
kullandığımız bölümleri bırakın. Aşağıdaki kodu yapıştırın.
// App.js // import custom hooks import { useFetch, useInfiniteScroll, useLazyLoading } from './customHooks' const imgReducer = (state, action) => { ... } // retain this const pageReducer = (state, action) => { ... } // retain this const [pager, pagerDispatch] = useReducer(pageReducer, { page: 0 }) // retain this const [imgData, imgDispatch] = useReducer(imgReducer,{ images:[], fetching: true }) // retain this let bottomBoundaryRef = useRef(null); useFetch(pager, imgDispatch); useLazyLoading('.card-img-top', imgData.images) useInfiniteScroll(bottomBoundaryRef, pagerDispatch); // retain the return block return ( ... )
Sonsuz kaydırma ile ilgili bölümde bottomBoundaryRef
hakkında zaten konuşmuştuk. pager
nesnesini ve imgDispatch
işlevini useFetch
. useLazyLoading
.card-img-top
sınıf adını kabul eder. not edin .
sınıf adına dahil edilmiştir. Bunu yaparak, bunu belirtmemize gerek yok document.querySelectorAll
. useInfiniteScroll
, page
değerini artırmak için hem bir başvuru hem de gönderme işlevini kabul eder.
Bu noktada karşılık gelen dal 04-özel kancadır.
Çözüm
HTML, harika özellikleri uygulamak için güzel API'ler sağlamada daha iyi hale geliyor. Bu yazıda, bir React fonksiyonel bileşeninde kesişim gözlemcisini kullanmanın ne kadar kolay olduğunu gördük. Bu süreçte, React'in bazı kancalarını nasıl kullanacağımızı ve kendi kancalarımızı nasıl yazacağımızı öğrendik.
Kaynaklar
- "Sonsuz Kaydırma + Görüntü Tembel Yükleme", Orji Chidi Matthew, GitHub
- “Sonsuz Kaydırma, Sayfalandırma veya “Daha Fazla Yükle” Düğmeleri? E-Ticarette Kullanılabilirlik Bulguları,” Christian Holst, Smashing Magazine
- “Lorem Picsum,” David Marby ve Nijiko Yonskai
- “IntersectionObserver Görüntülenmeye Geliyor,” Surma, Web Fundamentals
- Kullanabilir miyim…
IntersectionObserver
- "Kesişim Gözlemcisi API'si", MDN web belgeleri
- "Bileşenler ve Aksesuarlar", React
- "
useCallback
," Tepki - "
useReducer
," Tepki