사용자가 스크롤을 통하여 특정 영역에 도달하였을 때 새로운 데이터를 페칭하여 화면에 나타내는 것을 의미한다. 무한스크롤을 구현방법은 여러가지가 있으나 나는 Interserction Observer API를 활용하여 구현하였다.
타겟 요소와 상위 요소 또는 최상위 document의 viewport(현재 화면) 사이의 intersection 내의 변화를 비동기적으로 관찰하는 API이다. 즉, Intersection Observer란 화면 상에 내가 지정한 타겟 요소가 보이고 있는지 관찰하는 API이다.
const io = new IntersectionObserver(callback, options);
io.observe(element);
new IntersectionObserver()
를 통해 관찰자를 초기화하고 관찰할 element를 지정한다. 생성자는 2개의 인수 (callback
, options
)를 가진다.
const io = new IntersectionObserver((entries, observer) => {}, options)
io.observe(element)
관찰할 대상(target)이 등록되거나 가시성에 변화가 생기면 관찰자는 callback을 실행한다. callback은 2개의 인수(entries
, observer
)를 가진다.
boundingClientRect // viewport 기준으로 어느 위치에 있는지 측정
intersectionRect // element의 감지된 부분의 사각형 정보
intersectionRatio // element가 루트 요소와 얼마나 겹치는 지 0~1 사이
isIntersecting // element의 교차 상태
rootBounds // 루트 요소의 사각형 정보
target // element
time // element와 루트 요소의 교차 발생시간
observe(element) // 대상 요소 관찰 시작
unobserve(element) // 대상 요소 관찰 중단
disconnect() // 관찰하는 모든 요소 관찰 중단
root // target의 가시성을 확인할 때 사용되는 뷰포트 요소
rootMargin // root가 가진 바깥 여백
threshold // callback이 실행될 대상 요소의 가시성이 얼마나 필요한지 나타내는 값
const [list, setList] = useState([]);
const [target, setTarget] = useState(null);
const [qs, setQs] = useState({ pageNumber: 1 });
useEffect(() => {
// 데이터 페칭 로직
setList((prev) => {
return [...prev, ...result?.data?.list]
});
}, [qs]);
useEffect(() => {
let observer;
if (target) {
const callback = ([entry], observer) => {
if (entry.isIntersecting) {
setQs((prev) => {
return {
...prev,
pageNumber: prev?.pageNumber + 1,
}
})
observer.unobserve(target);
}
};
const options = { threshold: 1 };
observer = new IntersectionObserver(callback, options);
observer.observe(target);
}
return () => observer && observer.disconnect();
}, [target]);
return (
<>
<div>
{list?.map((item, index, arr) => {
return (
...
)
))}
</div>
<div ref={setTarget} />
</>
);