Intersection Observer

hoin_lee·2023년 3월 20일
0

TIL

목록 보기
162/236

Intersection Observer

자주 사용할 것 같아서 한 번 정리해야 될 것 같았다.
Web API중 하나로

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

MDN을 참고하면 이렇게 되어 있다.

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

사용이유

타겟이 화면에 노출 되었는지 여부를 간단하게 확인할 수 있는 API인데 만약 Intersection observer를 사용하지 않고 기능 구현한다면 이벤트리스터를 이용해 스크롤이 일어날 때마다 체크를 하거나 등 성능이슈를 개선하기 위해 많은 노력을 했을것이다.

사용법

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

// 타겟 요소 관측 시, 실행될 콜백 함수
const callback = (entries, observer) => {
  console.log('콜백함수');
};

// Observer 선언
const observer = new IntersectionObserver(callback, options);

// 타겟 요소 관측 시작
observer.observe(TargetElement);

// 타겟 요소 관측 중단
observer.unobserve(TargetElement);

// 모든 요소 관측 중단
observer.disconnect();

// 관측 중인 모든 요소를 배열 형태로 반환
observer.takeRecords();

Intersection Observer 에서 옵션객체는 말 그대로 옵션이기 때문에 선택사항이며 파라미터로 넘기지 않을 경우 기본 값이 적용된다.

intersection Observer 객체에서 사용 가능한 메서드

  • observe(파라미터로 targetElement)
    파라미터로 넘긴 타겟 요소에 대한 관측을 담당한다. 동일한 옵저버 객체로 여러번 호출을 해서 다양한 타겟 요소에 대해 관측이 가능하다.

  • unobserve(파라미터로 targetElement)
    타겟 요소에 대한 관측을 중지하는 역할을 담당.

  • disconnect
    모든 타겟 요소에 대한 관측을 중지한다.

  • takeRecord
    현재 관측 중인 모든 타겟 요소들을 배열 형태로 반환한다.

option

const option = {
  root:null,
  rootMargin: 0px,0px,0px,0px,
  threshold:0

default 값으로만 구성된 option객체의 예시이다

  • rpot(viewport) : 타겟 요소와 교차 영역을 정의하기 위해 사용하는 상위 요소 프로퍼티다.
    만약 값을 넣지 않거나 null일 경우에는 브라우저의 viewport(보여지고 있는 요소)가 root로 지정
  • rootMargin : root요소에 적용되는 margin값을 정의하기 위한 프로퍼티. 지정한 값만큼 교차 영역이 계산되며 루트의 범위가 축소하게 된다.
  • threhold란?
    • default:0
    • 0.0부터 1.0 사이의 숫자 혹은 이 숫자들로 이루어진 배열로, 타겟 엘리먼트에 대한 교차영역 비율을 의미
      0.0의 경우 타겟 엘리먼트가 교차 영역에 진입 했을 시점에 observer를 실행하는 것이고 1.0의 경우 타겟 엘리먼트 전체가 교차 영역에 들어왔을 때 observer를 실행하는 것!

그럼 이를 바탕으로 내 프로젝트에서 쓰일 무한 스크롤을 구현해보자

무한 스크롤 구현

  1. 데이터 패칭하기

    맨 처음 페이지를 들어왔을 때 데이터를 보여줘야 하기 때문에 axios를 이용한 데이터 함수를 만들었고 이는 계속해서 보여줘야 되니 state에 담아 축적시켰다.
  const getPostList = async (page: number) => {
    await axios
      .get(`/posts/${page}`)
      .then((res) => {
        setPostListItem((snap) => [...snap, ...res.data]);
      })
      .catch((err) => console.log(err))
      .finally(() => setLoading(false));
  };

url의 경우 일단 프록시 미들웨어를 사용중이기 때문에 적지 않았고 받는 데이터 구분을 page로 구분하기 위해 page를 인자로 받는다.

  1. 페이지 넘버를 바꾸는 함수를 만든다
  • getPostList로 데이터를 불러왔다면, page를 1씩 증가시켜서 그 다음 데이터를 불러오게 한다. 새롭게 불려진 데이터는 getPostList를 통해 기존 데이터에 더해진다.
  • loadMore함수를 만들어 page가 1씩 더해지는 함수를 만듬
const loadMore = () => {
		setPage(prev => prev + 1);
	}
//...생략
  1. useRef를 사용해 타겟 설정하기
  • 무한 스크롤은 마지막 엘리먼트에 닿았을 때 데이터를 자동으로 불러온다.
    페이지의 마지막 요소는 <Loding />로 해놨기에 ref를 지정해놓고 탐색 타겟으로 정해놓는다.
    이제 스크롤(화면)이 해당 엘리먼트에 도달했을 때 데이터를 패칭함
  1. Intersection Observer를 사용해서 뷰포트 안에 잇는 요소 확인하기
  • Intersection Observer를 통해 뷰포트 내에 지정해둔 타겟<Loding/>을 찾고 잇으면, 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]);
  
  ...생략

}

Reference
참고자료 1 - velog
참고자료 2 - velog

profile
https://mo-i-programmers.tistory.com/

0개의 댓글