IntersectionObserver 무한스크롤 (Infinite Scroll) 구현

Eom Deokhyeon·2024년 1월 11일
0
post-thumbnail

📌 무한스크롤(Infinite Scroll)

사용자가 스크롤을 통하여 특정 영역에 도달하였을 때 새로운 데이터를 페칭하여 화면에 나타내는 것을 의미한다. 무한스크롤을 구현방법은 여러가지가 있으나 나는 Interserction Observer API를 활용하여 구현하였다.

📌 Intersection Observer API

타겟 요소와 상위 요소 또는 최상위 document의 viewport(현재 화면) 사이의 intersection 내의 변화를 비동기적으로 관찰하는 API이다. 즉, Intersection Observer란 화면 상에 내가 지정한 타겟 요소가 보이고 있는지 관찰하는 API이다.

- intersection observer 생성

const io = new IntersectionObserver(callback, options);
io.observe(element);

new IntersectionObserver()를 통해 관찰자를 초기화하고 관찰할 element를 지정한다. 생성자는 2개의 인수 (callback, options)를 가진다.

- callback

const io = new IntersectionObserver((entries, observer) => {}, options)
io.observe(element)

관찰할 대상(target)이 등록되거나 가시성에 변화가 생기면 관찰자는 callback을 실행한다. callback은 2개의 인수(entries, observer)를 가진다.

- entries

boundingClientRect // viewport 기준으로 어느 위치에 있는지 측정
intersectionRect   // element의 감지된 부분의 사각형 정보
intersectionRatio  // element가 루트 요소와 얼마나 겹치는 지 0~1 사이
isIntersecting     // element의 교차 상태
rootBounds         // 루트 요소의 사각형 정보
target             // element
time               // element와 루트 요소의 교차 발생시간

- methods

observe(element)   // 대상 요소 관찰 시작
unobserve(element) // 대상 요소 관찰 중단
disconnect()       // 관찰하는 모든 요소 관찰 중단

- options

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} />
  </>
);

0개의 댓글

관련 채용 정보