최근 진행하고 있는 프로젝트에서 무한 스크롤 기능을 구현해야하는 부분이 있었는데, 해당 기능을 구현해본 적이 없어 이를 구현해보고 싶었고 구현을 위해 IntersectionObserver에 대해 공부하고 프로젝트에 적용하기로 했다.
const io = new IntersectionObserver(callback, options) // 관찰자 초기화
io.observe(el); // 관찰할 대상(요소)등록
// 프로젝트에서는 다음과 같이 활용
const observer = new IntersectionObserver(code...)
if(ref.currnet) observer.observe(ref.current);
const io = new IntersectionObserver((entries, observer) => {}, options)
io.observe(el);
boundingClientRect
: 관찰 대상의 사각형 정보 (전체 사각형의 정보) intersectionRect
: 관찰 대상의 교차한 영역 정보 (화면에 보여지는 사각형의 정보) intersectionRatio
: 관찰 대상의 교차한 영역 백분율 isIntersection
: 관찰 대상의 교차 상태(Boolean값) (루트의 전체 구역) rootBounds
: 지정한 루트 요소의 사각형 정보 target
: 관찰 대상 요소time
: 변경이 발생한 시간 정보 const io = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
console.log(entry) // entry is `IntersectionObserverEntry
})
}, options)
io.observe(el);
// 프로젝트 적용 방법
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
if (!checkLast) {
getBoards(page);
}
}
},
{ threshold: 0.5 }
);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
if (ref.current) {
observer.unobserve(ref.current);
}
};
}, [page]);
root
rootMargin
threshold
observe()
: 대상 요소의 관찰을 시작 const div = document.querySelector('div');
observer.observe(div); // div 요소 관찰
unobserve()
: 대상 요소의 관찰을 중지한다. observe.observe(div);
observe.unobserve(div);
disconnet()
: 모든 요소의 관찰을 중지 observe.observe(div);
observe.disconnect(); // observe가 관찰하는 모든 요소의 관찰을 중지
useRef()
를 사용하여 DOM을 선택하고 이를 활용하는 방식으로 구현했다. import {useEffect, useState, useRef} from 'react';
export function AllPost() {
const ref = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
if (!checkLast) {
getBoards(page);
}
}
},
{ threshold: 0.5 }
);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
if (ref.current) {
observer.unobserve(ref.current);
}
};
}, [page]);
//code..
return(
<>
//code..
{post ? post.map((item) => {
return (
<img src = {item.imageUrl}
key = {item.id}
onClick = {() => routePost(item.id)} />
);
}) : null}
<div ref = {ref} />
</>
}
해당 코드를 사용하여 위와 같이 구현할 수 있었다. 구현 도중 브레이크 포인트를 걸지 않아 API를 무한 호출했었는데, 마지막 페이지임을 확인하는 isLast를 api 조건문으로 체크하여 무한 호출하는 부분을 해결할 수 있었다.