React로 무한 스크롤 구현하기
3 min read
이번에는 react-intersection-observer
를 이용해서 무한 스크롤을 구현하는 방법을 알아가보도록 하겠습니다.
들어가기 앞서
많은 콘텐츠를 효과적으로 보여줄 수 있는 대표적 UI 에는 무한 스크롤
, 페이징
이 있습니다.
PC에서는 페이징
, 모바일에서는 무한 스크롤
UI 가 각각 더 사용자에게 편하게 다가옵니다. 하지만 최근에는 반응형 페이지를 통해서 PC와 모바일 모두 커버하는 경우가 많기 때문에 이번에는 무한 스크롤
을 함께 구현해보도록 하겠습니다.
구현
무한 스크롤
을 구현하는 방법은 여러가지가 있겠지만, 가장 확실한 방법은 마지막 요소가 사용자에게 보이면 다음 데이터를 불러오는 방법이 있습니다.react-intersection-observer
라이브러리를 사용하면 위와 같은 방법을 보다 쉽게 구현할 수 있습니다.
설치
yarn add react-intersection-observer
또는
npm i react-intersection-observer
사용 방법
import React from "react" import { useInView } from "react-intersection-observer" const App = () => { const [ref, inView] = useInView() return ( <div ref={ref}> Element {inView.toString()} </div> ) } export default App
ref
를 div에 걸어주면 해당 요소가 보이면 inView가 true
로, 안 보이면 false
로 자동으로 변경됩니다.
예제
// App.js import React, { useState, useEffect, useCallback } from "react" import { useInView } from "react-intersection-observer" import axios from "axios" const App = () => { const [items, setItems] = useState([]) const [page, setPage] = useState(1) const [loading, setLoading] = useState(false) const [ref, inView] = useInView() // 서버에서 아이템을 가지고 오는 함수 const getItems = useCallback(async () => { setLoading(true) await axios.get(`${Your Server Url}/page=${page}`).then((res) => { setItems(prevState => [...prevState, res]) }) setLoading(false) }, [page]) // `getItems` 가 바뀔 때 마다 함수 실행 useEffect(() => { getItems() }, [getItems]) useEffect(() => { // 사용자가 마지막 요소를 보고 있고, 로딩 중이 아니라면 if (inView && !loading) { setPage(prevState => prevState + 1) } }, [inView, loading]) return ( <div className="list"> {items.map((item, idx) => ( <React.Fragment key={idx}> {items.length - 1 == idx ? ( <div className="list-item" ref={ref}> {item.content} </div> ) : ( <div className="list-item"> {item.content} </div> ) </React.Fragment> ))
간단하게 예제를 만들어 보았습니다. 차근차근 코드를 보도록 하죠.
getItems
함수는 page
가 바뀔 때 마다 재생성 되는 함수입니다. 이 함수를 useEffect
에 대괄호 안에 넣어 getItems
함수가 바뀔 때 마다 getItems
를 실행하도록 하였습니다.
결론적으로
page
가 바뀔 때 마다 서버에 정보를 요청합니다. 다음 페이지를 불러오기 위해서는page
만 증가시키면 바로 다음 페이지에 관한 정보를 받아옵니다.
두 번째 useEffect
는 inView
가 바뀔 때마다 inView
가 true
이고, 로딩중이 아니라면 page
를 증가시킵니다.
마치며
스크롤을 계산하여 데이터를 불러오는 무한 스크롤 방식은 아이폰에서의 스크롤 이벤트가 다르게 적용되어 생각보다 까다로운 부분들이 많았는데 이 글을 보고 react-intersection-observer
를 사용하여 보다 쉽게 구현할 수 있었으면 좋겠습니다.