React-Intersection-Observer 라이브러리로 무한스크롤 구현하기

송은·2023년 8월 22일
0
post-thumbnail

이번에 프로젝트를 진행하면서 무한 스크롤로 아이템 리스트들을 보여주도록 구현하게 되어서 글을 작성하게 되었다.
🤔 라이브러리를 사용하지 않는다면, ref 를 이용해서 아이템을 담고있는 스크롤 영역의 높이를 구하고, 스크롤의 위치가 영역의 바닥에 닿으면 요청을 보내는 식으로 구현이 될 것 같은데,, 일단 이번 프로젝트 때 기간이 짧기도하고 호다닥 구현해보려고 라이브러리를 사용했다!

React-Intersection-Observer

React-Intersection-Observer 는 브라우저 viewport와 설정한 요소의 교차점을 관찰하여 요소가 viewport에 포함되는지 구별하는 기능을 제공한다.

  • 페이지 스크롤 시 이미지를 Lazy-loading 할 때
  • 무한 스크롤을 통해 새로운 컨텐츠를 불러올 때
  • 광고의 수익을 계산하기 위해 광고의 가시성을 참고할 때
  • 사용자가 결과를 볼 것인지에 따라 애니메이션 동작 여부를 결정할 때

📁 설치

yarn add react-intersection-observer

👉 Import

import { useInView } from 'react-intersection-observer';

const { ref, inView } = useInView();

👀 사용

const { ref, inView } = useInView();
.
.
.
return (
  // 관찰할 객체에 ref를 달아준다.
  <div ref={ref}>나를 지켜봐!</div>
);
console.log(inView, "관찰됐어!👀");

return (
  <ScrollArea>
      {itemList.map((item) => (
      <Item>{item.content}</Item>
      ))}
      {/* 관찰할 객체에 ref를 달아준다. */}
      <div ref={ref}>나를 지켜봐!</div>
  </ScrollArea>
);

스크롤 구역 <ScrollArea> 안에서 itemList<Item> 목록들 뒤에 관찰 객체가 붙어 있다.
이 아이템들을 스크롤을 내려서 모두 보고 난 뒤, 가장 아래에 있는 관찰 객체가 확인되면
inViewtrue로 바뀌면서 콘솔창에 출력되는 것을 확인할 수 있다!

🔥 무한스크롤 구현하기

이를 이용해서 무한 스크롤을 구현해보자! 무한스크롤 원리는 이렇다.

전체 아이템 리스트 데이터를 서버로부터 통째로 받아서 뿌려주는 작업은 렌더링하는데에도 시간이 소요된다.
그래서 서버로부터 데이터를 7개씩, 10개씩 일정 사이즈별로 짤라서 1, 2, 3 페이지 이런식으로 나눠서 데이터를 소분하여 전달받는 것이다.

  1. 서버로 페이지 번호와 사이즈를 넘겨주어 리스트 데이터를 요청하는 코드 설정
const [page, setPage] = useState(0); // 요청할 현재 페이지 상태값
const dispatch = useDispatch();

const getItem = () => {
  try {
      const res = axios.get(`/main?page=${page}&size=12`);
      dispatch(setItemList(res)); // 응답받은 데이터를 아이템 리스트로 저장
      setPage((prev) => prev + 1); // 이후 요청 시 다음 페이지 요청하도록 +1
  } catch (e) {
      console.log(e);
  }
};
  1. inView 가 아이템 리스트 제일 뒤에 있는 객체를 관찰할 때마다(스크롤 끝일 때) 서버에 다음 데이터를 요청하는 코드를 실행한다.
useEffect(() => {
  if (inView) {
      console.log(inView, "관찰됐어!👀");	
      getItem();
  }
}, [inView])
  1. 아이템 리스트 맨 뒤에 관찰할 객체를 넣어준다.
return (
  <ScrollArea>
      {itemList.map((item) => (
      <Item>{item.content}</Item>
      ))}
      {/* 관찰할 객체에 ref를 달아준다. */}
      <div ref={ref}>나를 지켜봐!</div>
  </ScrollArea>
);

✅ 전체 코드

import { useInView } from "react-intersection-observer";
import { useEffect, useState } from "react";

const Component = () => {
  const [page, setPage] = useState(0);
  const itemList = useSelector((state) => state.itemList);
  const dispatch = useDispatch();
  const { ref, inView } = useInView();

  const getItem = () => {
    try {
      const res = axios.get(`/main?page=${page}`);
      dispatch(setItemList(res)); // 응답받은 데이터를 아이템 리스트로 저장
      setPage((prev) => prev + 1); // 이후 요청 시 다음 페이지 요청하도록 +1
    } catch (e) {
      console.log(e);
    }
  };

  useEffect(() => {
    if (inView) {
      console.log(inView, "관찰됐어!👀");
      getItem();
    }
  }, [inView]);

  return (
    <ScrollArea>
      {itemList.map((item) => (
        <Item>{item.content}</Item>
      ))}
      {/* 관찰할 객체에 ref를 달아준다. */}
      <div ref={ref}>나를 지켜봐!</div>
    </ScrollArea>
  );
};

출처

profile
개발자

0개의 댓글