무한 스크롤(feat : useOnScreen)

윤강석·2023년 2월 13일
0

IntersectionObserver API 를 이용해서 component가 view 에 잡히는지 확인

intersectionObserver Api 를 hook 으로 처리하기 위해 아래처럼 코드 작성. (null type check 때문에 코드가 조잡해지긴 했다.)

import { RefObject, useEffect, useRef, useState } from 'react';

export function useOnScreen(ref: RefObject<HTMLElement>) {
  const observerRef = useRef<IntersectionObserver | null>(null);
  const [isOnScreen, setIsOnScreen] = useState(false);

  useEffect(() => {
    observerRef.current = new IntersectionObserver(([entry]) =>
      setIsOnScreen(entry.isIntersecting),
    );
  }, []);

  useEffect(() => {
    if (observerRef.current === null || ref.current === null) {
      return;
    }

    observerRef.current.observe(ref.current);

    return () => {
      if (observerRef.current === null) {
        return;
      }
      observerRef.current.disconnect();
    };
  }, [ref]);

  return isOnScreen;
}

무한 스크롤을 구현하고 싶은 컴포넌트 마지막 줄에 감지할 컴포넌트를 넣고 ref 로 isOnScreen 을 넣을 ref 를 넣어준다
(더이상 받아올 컨텐츠가 없으면 ref null 처리)

 <LastLine ref={curPage.current === -1 ? null : elementRef}></LastLine>

서버에 요청 보내기 전&후 처리 코드

//무한 페이지네이팅에 필요한 훅들
  const curPage = useRef<number>(0);
  const elementRef = useRef<HTMLDivElement>(null);
  const isOnScreen = useOnScreen(elementRef);
  const [isRequesting, setIsRequesting] = useState<boolean>(false);


  //뷰에 들어옴이 감지될 때 요청 보내기
  const getNewsContent = useCallback(async () => {
    setIsRequesting(true);
    try {
      const Previews: Array<Preview> = await NewsService.getPreviews(curPage.current);
      if (Previews.length === 0) {
        curPage.current = -1;
        return;
      }

      if (curPage.current === 0) {
        setPreviewsDefault(Previews);
      }
      curPage.current += 1;
      const newPreviews = curPreviews.concat(Previews);
      setCurPreviews(newPreviews);
      return 0;
    } catch (e) {
      console.error(e);
    } finally {
      setIsRequesting(false);
    }
  }, [curPreviews]);

  useEffect(() => {
    //요청 중이라면 보내지 않기
    if (isOnScreen === true && isRequesting === false) {
      getNewsContent();
    } else {
      return;
    }
  }, [isOnScreen]);

아직 버그난 건 없으나 날 때마다 수정함.

0개의 댓글