프로젝트/Next+TypeScript

[Taskify] 대시보드 상세 - 무한 스크롤

dev-hpk 2024. 12. 19. 01:09

라이브러리 없이 무한 스크롤 구현하기!!!

어떤 방식으로 구현할까 고민하다가 Intersection Observer API라는 좋은 기능을 찾았습니다.

Intersection Observer API는 상위 요소 또는 최상위 문서의 viewport와 대상 요소 사이의 변화를 비동기적으로 관찰할 수 있는 수단을 제공합니다.

 

기본 사용법

let options = {
  root: document.querySelector("#scrollArea"),
  rootMargin: "0px",
  threshold: 1.0,
};

let observer = new IntersectionObserver(callback, options);

 

컬럼과 댓글을 불러오는데 모두 사용하기 위해 커스텀 훅으로 관리하도록 만들어 보겠습니다.

import { useEffect, useRef } from 'react';

function useIntersectionObserver(callback: IntersectionObserverCallback) {
  // IntersectionObserver 인스턴스를 저장하는 ref
  const observerRef = useRef<IntersectionObserver | null>(null);
  // 관찰할 DOM 요소를 저장하는 ref
  const elementRef = useRef<HTMLDivElement | null>(null);

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

    observerRef.current = new IntersectionObserver(callback, {
      // 관찰 기준을 현재 요소의 부모로 설정
      root: elementRef.current.parentNode as Element,
      threshold: 0.95,
    });

    observerRef.current.observe(elementRef.current);

    // 컴포넌트 언마운트 시 Observer 연결 해제
    return () => observerRef.current?.disconnect();
  }, [callback]);

  return elementRef;
}

export default useIntersectionObserver;

 

이제 준비는 끝났습니다. 컴포넌트에 적용해 봅시다!!

PC 2개로 확인해 본 결과 반응형까지 모두 완벽하게 동작합니다!!!

 

이렇게 끝났으면 좋았을 텐데... 팀원 중 한 분이 테스트하다가 문제가 생겼다고 연락을 주셨습니다.

이상이 없길 바라는 마음으로 혹시 몰라 노트북으로 확인해 보니...

일부 사이즈 화면에서 Intersection Observer API가 동작하지 않았습니다.

 

일단 문제가 될 수 있는 상황부터 차근차근 찾아보았습니다. 고려해 볼 상황은 아래와 같습니다.

  • Viewport나 Root의 변경 감지 실패
    • 문제 상황 : 브라우저나 디바이스 사이즈가 변경되었을 때, IntersectionObserver는 자동으로 다시 계산되지 않을 수 있습니다.
    • 해결 방법 : resize 이벤트를 추가해서 브라우저 사이즈가 변경될 때마다 IntersectionObserver를 다시 생성하거나 갱신합니다.
    • 적용 결과 : 실패...😥
  • root 또는 target이 올바르게 설정되지 않음
    • 문제 상황 : root 요소를 명시적으로 설정했다면, 디바이스 사이즈가 변경될 때 root 요소의 사이즈가 달라질 수 있습니다. 이로 인해 IntersectionObserver가 예상과 다르게 동작할 수 있습니다.
    • 해결 방법 : root 요소의 사이즈가 변경될 때 옵저버를 갱신합니다.
      const endRef = useIntersectionObserver(handleObserver, rootRef);
    • 적용 결과 : 실패...😥
  • 비동기적 렌더링으로 타이밍 문제가 발생
    • 문제 상황 : API 요청으로 데이터를 받아와 DOM에 업데이트가 완료되기 전에 IntersectionObserver가 실행될 수 있습니다.
    • 해결 방법 : DOM이 업데이트가 완료되면 Intersection Observer가 실행될 수 있도록 수정합니다.
      const handleObserver = useCallback(
          ([entry]) => {
            if (entry.isIntersecting && columnData.cursorId && !isLoading)
              fetchCards(columnData.cursorId);
          },
          [fetchCards, columnData.cursorId, isLoading],
        );
    • 적용 결과 : 실패...😥

 

알아본 결과 내에서는 모두 해결하지 못했습니다...😭😭😭😭

멘토님께 피드백을 받은 결과 현업에서는 성능과 효율 측면에서 라이브러리를 사용하신다고 답변을 해주셨습니다.

 

react-intersection-observer

Monitor if a component is inside the viewport, using IntersectionObserver API. Latest version: 9.14.0, last published: 4 days ago. Start using react-intersection-observer in your project by running `npm i react-intersection-observer`. There are 1175 other

www.npmjs.com

 

라이브러리 없이 무한 스크롤을 구현해 봤다는 점에서 큰 성취감을 얻었습니다.

노트북을 제외한 대부분의 PC에서는 작동을 한다는 점에서는 만족하지만 모든 디바이스와 브라우저를 만족시키지 못한 점에서 아쉬움이 너무 커서 이 문제는 라이브러리가 어떤 방식으로 동작하는지 확인 후 수정하겠습니다🔥🔥🔥🔥

 

 

[Taskify] 대시보드 상세 페이지

오늘은 대시보드 페이지를 개발해 봤습니다.우선 전반적인 코드를 먼저 보여드리고 작업하면서 있었던 문제들과 해결한 방법에 대해서 설명해 볼게요! GET Columnsimport axios from '@/lib/instance';import

dev-hpk.tistory.com

 

 

[Taskify] Chip(공통 컴포넌트) 추가

오늘은 공통 컴포넌트 Chip을 개발해 보겠습니다.// Chip.tsimport { ReactNode } from 'react';type ChipType = 'tag' | 'status' | 'status-option';export interface ChipProps { children: ReactNode; chipType: ChipType;}export const bgTag = ['oran

dev-hpk.tistory.com