[React] IntersectionObserver으로 hooks만들기 (infinite scroll)

dev stefanCho·2022년 7월 2일
1

react

목록 보기
19/19
post-thumbnail
post-custom-banner

무한스크롤을 만들때 주로사용하는 IntersectionObserver를 예시와 함께 알아봅니다.

화면 예시

  1. 검색창에 책 제목을 검색합니다.
  2. 스크롤을 내리면 intersectionObserver에 의해서 http요청을 합니다.
  3. http 요청동안은 spinner가 돌아갑니다.

Code 예시

전체 코드는 github를 참고해주세요.

const CardList: FC<{ data: Docs[]; fetchMore: () => void }> = ({
  data,
  fetchMore,
}) => {
  const { lastItemRef } = useInfiniteScroll(fetchMore);

  return (
    <StyledCardList>
      {data?.map((book, index) => {
        if (index === data.length - 1) {
          return (
            <div ref={lastItemRef} key={index}>
              <CardItem book={book} />
            </div>
          );
        }
        return <CardItem book={book} key={index} />;
      })}
    </StyledCardList>
  );
};
import { useCallback, useRef } from 'react';

function useInfiniteScroll(fetchMore: () => any) {
  const observerRef = useRef<IntersectionObserver | null>(null);
  
  const lastItemRef = useCallback((node: HTMLDivElement) => {
    if (observerRef.current) {
      observerRef.current.disconnect();
    }

    observerRef.current = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        // fetch를 하기위한 callback
        fetchMore();
      }
    }, { rootMargin: '200% 0px' });
    
    if (node) {
      observerRef.current.observe(node);
    }
  }, []);

  return {
    lastItemRef,
  };
}

export default useInfiniteScroll;

useInfiniteScroll 코드 설명

useRef 사용

IntersectionObserver를 넣어둘 useRef를 생성합니다.
여기서의 useRef는 매번 새롭게 생성하는 IntersectionObserver를 담아둘 공간으로, 일반적으로 DOM을 참조하기 위한 목적이 아닙니다.

원하는 element에 lastItemRef를 넣어줍니다.

CardList 컴포넌트에서 마지막 CardItem에 ref에 lastItemRef를 넣어줍니다.

lasItemRef 작성하기

  • ref 함수 작성

    • <div ref={lastItemRef} key={index}><div ref={(ref) => lastItemRef(ref)} key={index}>와 같습니다. 즉 node element를 받게 됩니다.
      useInfiniteScroll에서 lastItemRef를 작성하게 되면 첫번째 parameter는 node element가 됩니다.
  • 기존 lastItem의 observe 중단

    • 기존에 관찰하던 node가 있다면 observerRef.current.disconnect();로 모든관찰을 중단합니다.
  • 새로운 IntersectionObserver 생성

    • observerRef.current = new IntersectionObserver으로 새로운 IntersectionObserver를 생성합니다. IntersectionObserver의 parameter는 두가지가 있습니다. (자세한 설명은 이 블로그를 참고해주세요.)
  • IntersectionObserver의 첫번째 parameter

    • callback fuction 입니다.
    • options 조건에 맞는 교차가 발생하면 실행됩니다.
    • entries는 교차가 발생하는 순간에 관찰(observe)하던 element가 들어갑니다. 예를들어, 화면예시에서는 한줄에 4개의 card가 있습니다. 모든 card를 관찰중이었다면, entries는 4개(빨간음영의 관찰중)가 들어가게 됩니다.
  • IntersectionObserver의 두번째 parameter

    • 옵션 (root, rootMargin, threshold를 지정)

정리

CardList를 생성할때 lastItemRef로 마지막 Item을 관찰합니다.
ref를 생성하면서 기존관찰을 모두 disconnect()하고, 내부에 new IntersectionObserver()를 생성합니다. 그리고 node를 관찰(observe(node))합니다.

관찰하던 node와 root의 교차(intersection)가 발생하면, IntersectionObserver의 callback이 실행됩니다.
callback함수에 의해 fetchMore이 실행됩니다.

Ref

profile
Front-end Developer
post-custom-banner

0개의 댓글