
대량의 데이터를 한번에 렌더링 하게 되면 사이트 사용중 느려짐이 발생할 수 있습니다. 그렇게 되면 사용자가 불편함을 느낄 수 있는데, 이를 방지하기 위해 데이터를 일정 개수 만큼씩만 가져오는 pagination을 구현해보려고 합니다.
다음은 무한 스크롤 형식으로 pagination을 구현하는 방법입니다.
pagination을 쉽게 구현하기 위해 react 라이브러리 react-intersection-observer를 사용하였습니다.
npm install react-intersection-observer --save
먼저, pagination으로 axios 요청하는 코드입니다.
// api.jsx
import axios from 'axios'
const axiosInstance = axios.create({
baseURL: BASEAPI,
});
function getNews(newsNum, pageNum, success, fail) {
// newsNum : 한번 부를 때 불러올 뉴스 데이터의 개수
// pageNum : 뉴스 데이터를 일정 개수로 자른 페이지 수
const newsUrl = (newsNum, pageNum) => `/articles/news?size=${newsNum}&page=${pageNum}
return axiosInstance.get(newsUrl)
.then(success)
.catch(fail)
}
export { getNews };
다음으로, 페이지네이션으로 데이터를 불러와 렌더링 하는 코드입니다.
useInView 훅을 사용해 구현합니다.
[ref, inView] = useInView()
import { useInView } from 'react-intersection-observer'
import { getNews } from '../api'
import { useRecoilState } from 'recoil'
import { newsDataState } from '../state/atoms'
export default function NewsDetail() {
// 렌더링 할 데이터
const [newsData, setNewsData] = useRecoilState(NewsDataState)
const [page, setPage] = useState(1)
const [ref, inView] = useInView()
// 처음 페이지에 진입했을 때 빈 페이지를 방지하기 위해
// 0 페이지의 데이터를 렌더링 합니다.
// 데이터는 10개씩 불러옵니다.
useEffect(() => {
getCategoryNews(
10, 0,
(response) => {
setNewsData(response.data)
},
( error ) => {
console.log(error)
}
)
}, [])
// 다음 페이지부터는 ref 객체가 보일 때 렌더링 됩니다.
useEffect(() => {
if (inView) {
getCategoryNews(
10, page,
( response ) => {
setCategoryData([...newsData, ...response.data])
setPage((page) => page + 1)
},
( error ) => {
console.log(error)
}
)
}
}, [inView])
return (
<div>
// 데이터가 있는 경우에만 렌더링
{newsData.length > 0 ?
newsData.map((data) => (
<div key={data.article_id}>
{data.title} - {data.content}
</div>
))
// 데이터가 없는 경우
: <div> 결과가 존재하지 않습니다. </div>}
<div ref={ref}></div> // 페이지를 내리다 이 객체가 보이면 새로운 데이터 렌더링
</div>
)
};
이렇게 하면 스크롤을 내리면서 ref 객체가 보일 때마다 새로운 데이터를 10개씩 불러올 수 있습니다.