본문 바로가기

Dev-FE

[WEB] #1. 무한스크롤 만들기

무한스크롤을 아직까지 사용해본 적은 없으나, 기술연습이나 과제 등으로 활용되어 정리하고자 함

#1. element 속성을 이용한 무한 스크롤
#2. Intersection Observer API를 이용한 무한 스크롤
  #2.1. IntersectionObserver API (component)
  #2.2. useIntersection Hook

#1. element 속성을 이용한 무한 스크롤

  • document.documentElement.scroll 속성을 이용하여 활용한 방식으로 예전에 많이 활용하던 방식
    • 리스트 중 특정 데이터 자동 포커싱 등에 활용
  • 그림1. 은 html로 그려지는 요소(element) 의 사이즈 속성 정보를 표현

그림 1. html element property

 

  • 브라우저에 나타나는 부분을 viewport 라고 볼 때, 
    • clientHeight: 해당 element의 높이 (offsetHeight, clientHeight의 차이는 추 후 설명)
    • scrollTop: 해당 현재 스크롤이 위치한 최상단 값
    • scrollHeight: 해당 element의 전체 높이 (스크롤이 없이 모두 보여줬을 때의 높이)
  • scrollHeight - scrollTop의 값과 clientHeight 값을 비교하여 스크롤이 아래로 내려갔을 때, 이벤트를 호출하여 무한스크롤 호출
    • scrollHeight - scrollTop <= clientHeight +  ꭤ
      • ꭤ: 버퍼값 (threshold)
/**
 * 스크롤 이벤트 함수
 */
const onScroll = () => {
  const st = document.documentElement.scrollTop;
  const sh = document.documentElement.scrollHeight;
  const ch = document.documentElement.clientHeight;
    
  if (sh - st <= (ch + 200)) { // ch + ꭤ; 버퍼 지정
    // 데이터 호출하기
    // ... 
  }
};

document.body.addEventListener('wheel', onScroll);	// desktop web
document.body.addEventListener('touchmove', onScroll);  // mobile web

 

  • 해당 코드를 이용한 무한스크롤 구동방식은 아래와 같음

See the Pen infinite-scroll by hee0 (@ryuheeyoung) on CodePen.

 

#2. Intersection Observer API를 이용한 무한 스크롤

  • IntersectionObserver API의 속성을 이용하여 viewport 상태를 체크하여 무한스크롤 구현

그림 2. intersectionObserver property

 

  •  IntersectionObserver() 로 옵저버 생성
    • root: 기본값은 viewport, 타겟이 포함된 노드로 지정 가능
    • rootMargin: root 노드의 마진값 설정
    • threshold: viewport와의 교차범위 (0~1) 설정

#2.1. intersectionObserver API (component)

  • intersectionObserver로 스크롤의 하단부에 타겟을 지정하고, 타겟이 viewport에 나타날 때 이벤트 호출
// 임의 element 생성 (target)
const target = document.createElement('div');
target.innerText = 'target';
 
const observer = new IntersectionObserver(([entry]) => {
  if (entry.isIntersecting) {
    // 데이터 처리
    // ...
  } 
}, {
  root,
  threshold,
  rootMargin,
});

observer.observe(target);

// ...

observer.disconnect();

 

  • 해당 코드를 이용한 무한스크롤 구동방식은 아래와 같음

See the Pen Untitled by hee0 (@ryuheeyoung) on CodePen.

 

#2.2. useIntersection hook

  • custom hook으로 활용
import { Ref, useCallback, useEffect, useRef, useState } from "react";

/**
 * useIntersection Hook
 * @param options
 * @returns
 */
const useIntersection = (
  options: IntersectionObserverInit
): { setRef: Ref<any>; isIntersecting: boolean } => {
  /**
   * 교차여부
   */
  const [isIntersecting, setIsIntersecting] = useState(false);
  /**
   * 타겟 변수
   */
  const ref = useRef(null);

  /**
   * 타켓 세팅 함수
   * @param el
   */
  const setRef = (el: Element) => {
    ref.current = el;
  };

  /**
   * 교차 관찰 콜백 합수
   */
  const onIntersection: IntersectionObserverCallback = useCallback(
    ([entry]) => {
      setIsIntersecting(entry.isIntersecting);
    },
    []
  );

  useEffect(() => {
    if (!ref.current) return;

    const observer = new IntersectionObserver(onIntersection, {
      ...options,
    });
    observer.observe(ref.current);

    return () => {
      observer.disconnect();
    };
  }, [options, onIntersection]);

  return { setRef, isIntersecting } as const;
};

export default useIntersection;

 

  • 사용방법은 간단
    • useIntersection hook 만든 후, 사용할 곳에서 hook을 호출하여 활용

작업한 무한스크롤 링크

 

GitHub - ryuheeyoung/next-ts-scroll: infinity scrolling with next.js

infinity scrolling with next.js. Contribute to ryuheeyoung/next-ts-scroll development by creating an account on GitHub.

github.com

 

infinite scroll

 

next-ts-scroll.vercel.app