항상 이론으로만 보다가, 한번쯤 직접 구현해보고 싶어서 제일 쉬운 예제를 따라해보았다.
(간단하게 기능만 구현하기위해 any type을 남발하였음...)
API 출처: https://unsplash.com/
const [photos, setPhotos] = useState<any>([])
const [pageNumber, setPageNumber] = useState<number>(1)
photo: 불러온 데이터를 저장
pageNumber: 불러올 API의 page query
const fetchPhotos = async (pageNumber: number) => {
const res = await fetch(`${API_URL}=${Access_Key}&page=${pageNumber}`)
const data = await res.json()
setPhotos((photo: any) => [...photo, ...data])
}
useEffect(() => {
fetchPhotos(pageNumber)
}, [pageNumber])
const loadMore = () => setPageNumber((prev) => prev + 1)
쉽게 생각하여 버튼에 onClick속성으로 loadMore함수를 작성해주면, 버튼을 누를 때 데이터를 불러오게 되는 것이다.
이렇게 되면 무한 스크롤은 아니지만 버튼 클릭에 따른 데이터 불러오기는 할 수 있다. 이렇게 세팅을 완료한 후 Intersection Observer를 통해 무한 스크롤을 본격적으로 구현해 보도록 하자.
const pageEnd = useRef<any>()
useEffect(() => {
const observer = new IntersectionObserver((entries: any) => {
if (entries[0].isIntersecting) {
loadMore()
}
}, { threshold: 1 })
observer.observe(pageEnd?.current)
}, [])
여기서 entries, 즉 entries[0].isIntersecting는 useRef를 통해 div에서 ref로 지정한 블록에 닿을 때 true, 그렇지 않을 때 false값이 나온다.
쉽게 말해서 마지막 블록에 닿아서 loading이 필요할 때 entries[0].isIntersecting : true,
그 외의 경우는 entries[0].isIntersecting : false값이라는 말이다.
그렇기 때문에 entries[0].isIntersecting가 true일 때 loadMore함수를 실행시켜 주는 것이다.
아까와 흐름은 동일하지만 이번엔 버튼을 눌렀을 때 loadMore함수가 실행되는것이 아닌, 버튼을 감싸는 div가 화면에 잡혀서 끝날 경우 loadMore함수가 실행되는 것을 볼 수 있다. 그렇게 되면 아주 간단하게나마 무한스크롤을 구현할 수 있다!
root, rootMargin, threshold 등 여러 옵션이 있지만 해당 포스팅에서는 기본적인 것만 구현하였으므로 다른 옵션들이 궁금하다면 공식문서를 참고하도록 해보자!