[React]Intersection Observer 사용하여 무한스크롤 구현하기

sujin·2022년 10월 9일
9

React

목록 보기
14/16
post-thumbnail

무한스크롤을 구현하는데 라이브러리가 존재하긴 했지만, Intersection Observer API를 사용하여 만들 수 있다고 하여 시도해봤다. 그렇다면 우선 Intersection Observer가 무엇인지부터 살펴보도록 하자.

1. Intersection Observer 란?

Web API중 하나인 Intersection Observer API는 크롬 51버전부터 사용할수 있으며, 2016년 구글 개발자 페이지를 통해 소개되었다고 한다. MDN에서는 Intersection Observer의 필요성을 아래와 같은 예를 들어 설명하고 있다.

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

정리하자면, Intersection observer는 기본적으로 브라우저 뷰포트(Viewport)와 설정한 요소(Element)의 교차점을 관찰하며, 요소가 뷰포트에 포함되는지 포함되지 않는지, 더 쉽게는 사용자 화면에 지금 보이는 요소인지 아닌지를 구별하는 기능을 제공한다.

1-1) Intersection Observer 사용이유

위에서 intersection observertarget element가 화면에 노출되었는지 여부를 간단하게 구독할 수 있는 API라고 정리했다.
만약 intersection observer를 사용하지 않고 기능을 구현한다면, scroll이 일어날 때 마다 특정 element가 화면에 존재하는지에 대한 여부를 계속 계산하는 코드를 만들어 줘야할 것이다.

1-2) Intersection Observer 생성

intersection observer를 생성하기 위해서 생성자 호출 시 콜백 함수를 제공해야한다. 이 콜백 함수는 threhold가 한방향 혹은 다른 방향으로 교차 할 때 실행된다.

threhold 란?

  • default: 0
  • 0.0부터 1.0 사이의 숫자 혹은 이 숫자들로 이루어진 배열로, 타겟 엘리먼트에 대한 교차 영역 비율을 의미한다. 0.0의 경우 타겟 엘리먼트가 교차영역에 진입했을 시점에 observer를 실행하는 것을 의미하고, 1.0의 경우 타켓 엘리먼트 전체가 교차영역에 들어왔을 때 observer를 실행하는 것을 의미한다.

2. 무한 스크롤 구현하기

2-1) 데이터 패칭하기

  • fetch함수를 이용해서 데이터를 불러오는 함수 fetchPins를 만들어준다. 무한 스크롤을 구현하기 위해서는 데이터를 처음부터 계속 보여줘야하기 때문에 데이터를 담고 있는 state인 pins 를 operator연산자로 복제해서 축적시켜줬다.
  • 스크롤이 닿았을 때 새롭게 데이터 페이지를 바꾸는 state인 page를 만들어준다. 그리고 useEffect로 page의 넘버가 바뀔 때마다 fetchPins 함수를 호출시킨다.

아직 백엔드 통신전이라서 데이터를 불러오는 api는 unsplash에서 제공해주는 api를 사용했다. 참고

const Main = () => {
  const [pins, setPins] = useState([]);
  const [page, setPage] = useState(1); //스크롤이 닿았을 때 새롭게 데이터 페이지를 바꿀 state
  const [loading, setLoading] = useState(false); //로딩 성공, 실패를 담을 state
  
  const fetchPins = async page => {
    const API_KEY = "API KEY 입력";
    const res = await fetch(
      `https://api.unsplash.com/photos/?client_id=${API_KEY}&page=${page}&per_page=10`
    );
    const data = await res.json();
    setPins(prev => [...prev, ...data]);
    setLoading(true);
  };
  
  useEffect(() => {
    fetchPins(page);
  }, [page]);
  
  ...생략
  

}

2-2) page넘버를 자꾸는 함수 만들기

  • fetchPins를 실행시켜 데이터를 불러왔다면, page를 1씩 증가시켜서 그 다음 데이터를 불러오도록 한다. 새롭게 불러와진 데이터는 fetchPins를 통해서 기존에 있던 데이터에 더해지게 된다.
  • loadMore함수를 만들어서 page가 1씩 더해지는 함수를 만든다.
const Main = () => {
	const loadMore = () => {
		setPage(prev => prev + 1);
	}
    ...생략
}

2-3) useRef를 사용한 target설정하기

  • 무한 스크롤은 마지막 엘리먼트에 닿았을 때 데이터를 자동으로 불러온다. 이 페이지의 마지막 요소는 <Loading/> 이기 때문에 여기에 ref를 지정해놓고 탐색 타겟으로 정해 놓는다. 여기에 도달했을 때 데이터 패칭을 시킨다.
import { useRef } from "react";

const Main = () => {
	const pageEnd = useRef();
  
  ...생략 
  
  return(
    ...생략 
  	<Loading ref={pageEnd} />
  )
}

2-4) Intersection Observer를 사용해서 뷰포트 안에 있는 요소 확인하기

  • Intersection Observer를 통해서 뷰포트 내에 지정해둔 타겟 <Loading/>를 찾고 있으면, loadMore함수를 실행시켜 page를 1씩 증가시키도록 한다.
const Main = () => {
  ...생략 
  
	useEffect(() => {
    if (loading) {
      //로딩되었을 때만 실행
      const observer = new IntersectionObserver(
        entries => {
          if (entries[0].isIntersecting) {
            loadMore();
          }
        },
        { threshold: 1 }
      );
      //옵져버 탐색 시작
      observer.observe(pageEnd.current);
    }
  }, [loading]);
  
  ...생략

}


마무리✨

무한 스크롤 기능을 구현하기 위해서 Intersection Observer를 처음 사용해봤다. 무한 스크롤 기능을 구현하고자 했을 때 처음에는 무작정 라이브러리만 찾았는데 Intersection Observer를 이해하고 나니 라이브러리 없이도 구현할 수 있을 것 같았고 덕분에 이 부분을 더 잘 이해하고 넘어 갈 수 있었던 것 같다.

profile
개발댕발

2개의 댓글

comment-user-thumbnail
2023년 6월 28일

포스트 잘 봤습니다!
데모 키라 크게 상관 없을 것 같기는 하지만 중간에 api key 노출된 부분은 수정하시는 게 좋지 않을까요?

1개의 답글