이번에 프로젝트를 진행하면서 무한 스크롤로 아이템 리스트들을 보여주도록 구현하게 되어서 글을 작성하게 되었다.
🤔 라이브러리를 사용하지 않는다면,ref
를 이용해서 아이템을 담고있는 스크롤 영역의 높이를 구하고, 스크롤의 위치가 영역의 바닥에 닿으면 요청을 보내는 식으로 구현이 될 것 같은데,, 일단 이번 프로젝트 때 기간이 짧기도하고 호다닥 구현해보려고 라이브러리를 사용했다!
React-Intersection-Observer 는 브라우저 viewport와 설정한 요소의 교차점을 관찰하여 요소가 viewport에 포함되는지 구별하는 기능을 제공한다.
yarn add react-intersection-observer
import { useInView } from 'react-intersection-observer';
const { ref, inView } = useInView();
const { ref, inView } = useInView();
.
.
.
return (
// 관찰할 객체에 ref를 달아준다.
<div ref={ref}>나를 지켜봐!</div>
);
console.log(inView, "관찰됐어!👀");
return (
<ScrollArea>
{itemList.map((item) => (
<Item>{item.content}</Item>
))}
{/* 관찰할 객체에 ref를 달아준다. */}
<div ref={ref}>나를 지켜봐!</div>
</ScrollArea>
);
스크롤 구역 <ScrollArea>
안에서 itemList
의 <Item>
목록들 뒤에 관찰 객체가 붙어 있다.
이 아이템들을 스크롤을 내려서 모두 보고 난 뒤, 가장 아래에 있는 관찰 객체가 확인되면
inView
가 true
로 바뀌면서 콘솔창에 출력되는 것을 확인할 수 있다!
이를 이용해서 무한 스크롤을 구현해보자! 무한스크롤 원리는 이렇다.
전체 아이템 리스트 데이터를 서버로부터 통째로 받아서 뿌려주는 작업은 렌더링하는데에도 시간이 소요된다.
그래서 서버로부터 데이터를 7개씩, 10개씩 일정 사이즈별로 짤라서 1, 2, 3 페이지 이런식으로 나눠서 데이터를 소분하여 전달받는 것이다.
const [page, setPage] = useState(0); // 요청할 현재 페이지 상태값
const dispatch = useDispatch();
const getItem = () => {
try {
const res = axios.get(`/main?page=${page}&size=12`);
dispatch(setItemList(res)); // 응답받은 데이터를 아이템 리스트로 저장
setPage((prev) => prev + 1); // 이후 요청 시 다음 페이지 요청하도록 +1
} catch (e) {
console.log(e);
}
};
inView
가 아이템 리스트 제일 뒤에 있는 객체를 관찰할 때마다(스크롤 끝일 때) 서버에 다음 데이터를 요청하는 코드를 실행한다.useEffect(() => {
if (inView) {
console.log(inView, "관찰됐어!👀");
getItem();
}
}, [inView])
return (
<ScrollArea>
{itemList.map((item) => (
<Item>{item.content}</Item>
))}
{/* 관찰할 객체에 ref를 달아준다. */}
<div ref={ref}>나를 지켜봐!</div>
</ScrollArea>
);
✅ 전체 코드
import { useInView } from "react-intersection-observer";
import { useEffect, useState } from "react";
const Component = () => {
const [page, setPage] = useState(0);
const itemList = useSelector((state) => state.itemList);
const dispatch = useDispatch();
const { ref, inView } = useInView();
const getItem = () => {
try {
const res = axios.get(`/main?page=${page}`);
dispatch(setItemList(res)); // 응답받은 데이터를 아이템 리스트로 저장
setPage((prev) => prev + 1); // 이후 요청 시 다음 페이지 요청하도록 +1
} catch (e) {
console.log(e);
}
};
useEffect(() => {
if (inView) {
console.log(inView, "관찰됐어!👀");
getItem();
}
}, [inView]);
return (
<ScrollArea>
{itemList.map((item) => (
<Item>{item.content}</Item>
))}
{/* 관찰할 객체에 ref를 달아준다. */}
<div ref={ref}>나를 지켜봐!</div>
</ScrollArea>
);
};
출처