[React] 무한스크롤 (IntersectionObserver)

김현철·2023년 4월 6일
0
post-thumbnail

응애 개발자 국룰코스 영화 및 책 검색 사이트를 만드는 중 무한 스크롤 기능을 구현해보았다.

여러가지 방법이 있었지만 IntersectionObserver라는 api를 사용하는 방법을 택했다
(사실 handleScroll이벤트와 throttle로직을 이용해 구현했었지만.... X망)


 const observer = useRef<IntersectionObserver>();

IntersectionObserver객체를 저장할 변수를 useRef를 사용하여 만들었다.


  <Grid container columnSpacing={{ xs: 1, sm: 2, md: 3 }} rowSpacing={5}>
        {books.map((items: any, index: number) => {
          if (books.length === index + 1) {
            return (
              <Grid ref={lastBook} xs={12} sm={6} md={4} key={items.isbn} item>
                <BookCard
                  discount={items.discount}
                  image={items.image}
                  isbn={items.isbn}
                  description={items.description}
                  publisher={items.publisher}
                  author={items.author}
                  title={items.title}
                />
              </Grid>
            );
          } else {
            return (
              <Grid xs={12} sm={6} md={4} key={items.isbn} item>
                <BookCard
                  discount={items.discount}
                  image={items.image}
                  isbn={items.isbn}
                  description={items.description}
                  publisher={items.publisher}
                  author={items.author}
                  title={items.title}
                />
              </Grid>
            );
          }
        })}
      </Grid>

책의 갯수만큼 Grid 아이템 컴포넌트를 생성하였고 마지막 아이템의 ref에는 lastBook함수를 할당했다.
해당 Grid 아이템 컴포넌트는 렌더링될때마다 ref에 할당된 lastBook을 실행하게된다.


// lastBook 함수를 useCallback을 사용하여 선언했다.
// display는 40이다 본인은 아이템을 40개씩 가져왔기때문에..
// maxPage는 api에서 가져온 아이템들의 갯수다.(드래곤볼의 경우 207개의 아이템이 있었다..)
// start는 시작페이지이다 api에 시작페이지를 알려줘야 다른아이템을 가져올 수 있다..

const lastBook = useCallback(
    (node: HTMLDivElement ) => {
      if (loading) return;
      if (observer.current) observer.current.disconnect();
      observer.current = new IntersectionObserver((entris) => {
        if (entris[0].isIntersecting && !isLastPage) {
          if (maxPage - display < start) {
            dispatch(setLastPage(true));
          } else {
            dispatch(changeStart(start + display));
          }
        }
      });
      if (node) observer.current.observe(node);
    },
    [loading, maxPage]
  );

useCallback을 사용하여 lastBook함수를 만들었다.
의존성배열에 loading과 maxPage를 넣어 로딩시 혹은 다른 검색어를 검색하여 maxPage가변경되었을때 함수가 업데이트 되도록 하였다.

node는 ref가 할당된 Grid컴포넌트다.

1.로딩중에는 함수가 실행되지 않게 하였다.

2.관찰 대상 요소와의 연결을 끊는 disconnect매소드를 사용하여 이전에 감시하던 대상을 제거하였다.

3.new IntersectionObserver 객체를 생성하였다. entris는 콜백함수가 호출되었을때 전달된 IntersectionObserverEntry 객체를 나타낸다

4.첫번째로 전달된 IntersectionObserverEntry 객체가 isIntersecting 상태고 api로 더이상 불러올 페이지가 없는게 아니라면 실행되게하였다.
(isIntersecting은 요소와 뷰포트가 교차되는지 여부를 나타내는 불리언 값이다..)

5.남은 페이지 수가 40 이하라면 isLastPage 값을 true로 설정했다.

6.그렇지않을경우 상태값을 업데이트해서 아이템40개를 더 불러오도록 하였다.

7.node를 관찰 대상으로 추가하였다.(관찰요소로 여러개를 추가할 수 있는것 같지만 여기선 하나만 사용했습니다.. entris[0]인 이유..)


IntersectionObserver 이녀석 이미지로딩이나 다른곳에서도 왕왕 쓰이는 것 같다 이번엔 맛보기 수준으로만 사용 했지만 깊이들어가면 알아야 할게 더 많은녀석인거같다 무서운녀석.. 기억해두자

profile
응애입니다.

0개의 댓글