infinite scroll (feat. Intersection Observer API)

HYUK·2023년 6월 7일
0

1. 이슈

이번 프로젝트 과정에 있어서 대부분의 스크롤이 필요한 부분에 있어서는 무한스크롤로 구현하기로 하였고 그 중 댓글의경우 많은 유저들이 소통하는 장소이기 때문에 댓글리스트에 가장먼저 무한스크롤을 구현하기로 하였다.

2. 구현과정

2-1. Scroll Event & Intersection Observer API

먼저 무한스크롤을 구현함에 있어서 다양한 참고자료를 찾아보던중 일반적으로 Scroll Event와 Intersection Observer API 이렇게 두가지방법이 눈에 띄엇고 이 두가지중 Intersection Observer API를 많이 권하고 있었다. 그 이유에 대해서는 아래 정리를 하였다.

2-1-1. Scroll Event & Intersection Observer API 장단점

1.Scroll Event:

Scroll Event는 웹 페이지가 스크롤될 때 발생하는 이벤트를 감지하는 기능이다. 스크롤 이벤트를 사용하여 무한 스크롤을 구현할 수 있지만, 몇 가지 주의할 점이 있다.

1). 장점

  • 쉽게 구현할 수 있다. Scroll Event를 감지하고 이벤트 핸들러를 사용하여 새로운 콘텐츠를 로드하는 것이 비교적 간단하다.

2). 단점

  • Scroll Event는 많은 이벤트를 발생시키므로 성능에 영향을 줄 수 있다. 스크롤링이 느려지거나 부자연스러워질 수 있다.
  • 모든 스크롤 이벤트를 처리해야 하므로, 스크롤 이벤트 핸들러를 최적화해야 한다.
  • 모바일 기기에서는 특히 스크롤 이벤트가 더욱 느릴 수 있다.

2. Intersection Observer API

Intersection Observer API는 요소의 가시성 변경을 관찰하는 기능을 제공한다. 특정 요소가 뷰포트에 들어오거나 나갈 때 이를 감지할 수 있다.

1). 장점

  • 성능 측면에서 더 효율적이다. Intersection Observer API는 브라우저 내부에서 최적화되어 있으므로 스크롤 이벤트보다 부하가 적다.
  • Intersection Observer API는 비동기적으로 작동하므로 메인 스레드의 블로킹을 최소화할 수 있다.
  • 뷰포트에 나타나는 요소를 관찰하기 때문에 정확하고 유연한 제어가 가능하다.

2). 단점

  • 구형 브라우저에서는 지원되지 않을 수 있다. 하지만 대부분의 최신 브라우저에서는 지원된다.

결론적으로, Intersection Observer API가 더 효율적이고 권장되는 방법이다. 성능 측면에서 더 우수하며, 비동기적으로 작동하기 때문에 부드러운 스크롤 경험을 제공할 수 있다. 하지만 구형 브라우저에서는 지원되지 않을 수 있으므로, 이를 고려하여 구현해야 한다.

2-2 Intersection Observer API

여러가지 내용을 고려했을때 Intersection Observer API로 구현하는게 맞다고 생각이 들어 Intersection Observer API로 구현하는것을 목표로 잡고 시작하였다.
무한스크롤 구현이 처음이라 스크롤이 최하단에 닿았을때 이것을 어떻게, 어떤방법으로 감지를하고 구현을하는지 전혀 감이 잡히지 않았는데 여러 참고자료를 찾아보니 useRef 훅을 사용하여 스크롤을 감지할 요소를 생성하는것이였다.

 const observerRef = useRef<HTMLDivElement>(null);

이러한식으로 useRef훅을 이용하여 감지요소를 변수에 담아 생성해 주었고 다음은 useEffect를 사용하여 Intersection Observer를 생성하였다.

useEffect(() => {
  const observerOptions = {
    root: null,
    rootMargin: '0px',
    threshold: 1.0,
  };

  const observer = new IntersectionObserver(entries => {
    const [entry] = entries;
    if (entry.isIntersecting) {
      // 스크롤이 감지되면 추가적인 데이터를 불러올 수 있는 함수 호출
      loadMoreComments();
    }
  }, observerOptions);

  if (observerRef.current) {
    observer.observe(observerRef.current);
  }

  return () => {
    if (observerRef.current) {
      observer.unobserve(observerRef.current);
    }
  };
}, [commentsData]);

useEffect 훅을 이용하여 commentsData가 변경될때마다 실행되는데, 코드에서 commentsData가 변경될 때마다 스크롤을 감지하여 추가 데이터를 불러오고있다.
observerOptinos를 보게 되면 threshold 값이 1.0으로 설정되었으므로, 타겟 요소가 100% 보이는 영역에 들어왔을 때 콜백 함수가 실행된다. 콜백 함수에서는 entry.isIntersecting을 확인하여 요소가 보이는지 여부를 확인하고, 보이는 경우 loadMoreComments함수를 호출하여 추가 데이터를 불러온다.loadMoreComments함수의 내용은 아래 내용과같다.

...

const [noMoreComment, setNoMoreComment] = useState(true); // 플래그: 더 이상 데이터가 없는지 여부

...

  const loadMoreComments = () => {
    if (!noMoreComment) {
      return; // 더 이상 데이터가 없으면 중지
    }

    const startIndex = commentsData.length; // 현재 commentsData의 길이를 가져옵니다.
    const endIndex = startIndex + 12; // 가져올 댓글의 끝 인덱스를 계산합니다.

    fetch(
      `${API.GET_POSTING_COMMENTS}/${params.id}?startIndex=${startIndex}&endIndex=${endIndex}`,
      {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json;charset=utf-8',
          Authorization: localStorage.getItem('access_token') || '',
        },
      }
    )
      .then(res => res.json())
      .then(data => {
        if (data.feedComment.length === 0) {
          setNoMoreComment(false); // 더 이상 데이터가 없음을 표시
        } else {
          setCommentsData([...commentsData, ...data.feedComment]);
        } // 새로운 댓글을 기존의 commentsData에 추가합니다.
      });
  };

loadMoreComments함수는 서버로 HTTP GET 요청을 보내어 추가 댓글 데이터를 가져온다. 데이터를 가져온 후에는 setCommentsDat함수를 사용하여 기존의 commentsData 배열에 새로운 댓글을 추가하는 과정인데 두 번째 .then() 메서드에서는 가져온 데이터를 확인하여 data.feedComment.length가 0인 경우, 더 이상 가져올 데이터가 없으므로 setNoMoreComment(false)를 호출하여 플래그를 변경한다. 그래서 다음 스크롤 작동시 !noMoreComment인 경우에는 더이상 fetch가 되지 않도록 구현하였다.

3. 정리

처음구현하는 기능이다보니 쉽지않았다. 그러나 많이쓰이는 기능이고 그렇다보니 다양한 참고문서들을 찾을 수 있어서 다행히 원하는대로 구현할 수 있었다. 방법은 다양하고 참고할 문서들은 정말 다양한데 이중에서 어떤게 더 효율적이고 안정성이 있는지에 대한 판단을 할수있는것도 중요하다는 것을 다시한번 느낀것같다. 또한 참고문서를 읽어내려감에 있어서 천천히 정독하며 이해해 나아가며 구현하는것 역시 구현과정에 있어서 중요하다는걸 다시한번 새삼 느낄수 있게 되었다. 급하다고 당장 코드만 찾아서 보는것이 아닌 하나하나 천천히 읽어내려가는 습관을 꾸준히 길러야겠다.

profile
step by step

0개의 댓글