[React] Intersection Object API 에 대해서 기록하기

김현수·2024년 2월 27일
0

React

목록 보기
16/29


🖋️ Intersection Object API 기록하기


설명

  • Intersection Observer API의 주요 기능은 개발자가 뷰포트에서의 존재 여부에 따라 요소의 "가시성과 모양을 제어" 할 수 있도록 하는 것

  • "관찰된 요소가 뷰포트에 들어오거나 나가면 API는 콜백을 트리거" 콘텐츠, 애니메이션 또는 작업을 로드하는 데 사용


대표 사용 예시 => "무한 스크롤"

  • Observer 만들기

    • 관찰된 요소가 뷰포트에 들어오거나 나갈 때마다 실행되는 콜백 함수를 정의

    • 각각 하나의 관찰된 요소를 나타내는 IntersectionObserverEntry 객체의 목록을 받음

    • 콜백 함수와 가시성에 대한 근 여백과 임계값을 정의 가능한 선택적 options 객체를 전달하여 IntersectionObserver 인스턴스를 생성
  • 대상 요소 관찰

    • React의 ref 속성을 사용하여 감시 역할을 하는 DOM 요소에 대한 참조
    • 트리거해야 하는 위치에 대한 마커
    • IntersectionObserver 인스턴스의 observe 메서드를 사용하여 감시 관찰을 시작
  • 더 많은 콘텐츠 로드

    • 콜백 내에서 로직을 구현하여 감시되는 시점을 결정하고 더 많은 콘텐츠 로드를 트리거
    • 여기에는 IntersectionObserverEntry 개체의 isIntersecting 속성 확인이 포함되는 경우가 많음
  • 정리

    • 메모리 누수를 방지
    • 컴포넌트가 탑재되지 않을 때 "관찰자의 연결을 끊는 것" 이 중요
    • 이 작업은 수명 주기 메서드 componentWillUnmount 또는 useEffect 후크의 정리 함수에서 수행 가능
import React, { useState, useEffect, useRef } from 'react';

const InfiniteScrollComponent = () => {
  // contents 목록을 보유하는 상태
  const [items, setItems] = useState([]);
  // 현재 더 많은 contents 를 로드하고 있는지 추적하는 상태
  const [loading, setLoading] = useState(false);

  // 목록 하단에 있는 감시 요소에 대한 참조
  const sentinelRef = useRef(null);

  // 더 많은 항목 가져오기를 시뮬레이션하는 더미 기능
  const fetchMoreItems = () => {
    // 1초 지연후 패칭 시뮬레이션
    setTimeout(() => {
      ... (데이터 패칭 로직) ...
      
      setItems(items.concat(newItems));
      setLoading(false); // Loading 이 완료되면 false
    }, 1000);
  };

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        // 감시한 값이 확인될 때
        if (entries[0].isIntersecting && !loading) {
          setLoading(true); // 다중 패치 막기
          fetchMoreItems(); // 패치
        }
      },
      {
        root: null, // null 은 viewport 를 사용한다는 의미
        rootMargin: '0px',
        threshold: 0.1, // 감시받는 요소의 10%가 보일 때 트리거
      }
    );

    if (sentinelRef.current) {
      observer.observe(sentinelRef.current);
    }

    // 정리
    return () => {
      if (sentinelRef.current) {
        observer.unobserve(sentinelRef.current);
      }
    };
  }, [loading, items]);

  return (
    <div>
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
      {/* 더 많은 컨텐츠를 로드하기 위한 감지요소를 관찰 */}
      <div ref={sentinelRef}>Loading more...</div>
    </div>
  );
};

export default InfiniteScrollComponent;


Q. WHEN 사용 ?

  • A1. "이미지를 Lazy-Loading 할 때"
  • A2. "무한 스크롤에서 데이터 패칭할 때"
  • A3. "광고의 가시성 참고할 때"
  • A4. "애니메이션 동작 여부 결정할 때"
  • 이미지 Lazy Loading

이미지가 사용자의 화면에 들어올 때만 
이미지를 로딩하도록 설정

=> 초기 페이지 로드 시 필요하지 않은 
이미지 리소스를 로드하지 않음으로써 성능을 향상
import React, { useState, useEffect, useRef } from 'react';

const LazyImage = ({ src, alt, ...props }) => {
  const [isVisible, setIsVisible] = useState(false);
  const imgRef = useRef();

  useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      if (entries[0].isIntersecting) {
        setIsVisible(true);
        observer.disconnect();
      }
    });

    observer.observe(imgRef.current);
    return () => observer.disconnect();
  }, []);

  return <img ref={imgRef} src={isVisible ? src : undefined} alt={alt} {...props} />;
};

  • 무한 스크롤에서 데이터 패칭할 때

스크롤이 페이지 하단에 도달할 때 
추가 데이터를 로드

=> 페이지의 성능을 유지하면서 
사용자가 더 많은 컨텐츠를 탐색

  • 광고의 가시성 참고할 때

광고가 뷰포트에 들어왔는지 확인하여 
광고의 가시성을 향상시키거나 
광고 성능 데이터를 수집
import React, { useEffect, useRef } from 'react';

const AdComponent = () => {
  const adRef = useRef();

  useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          console.log('Ad is visible.');
        }
      });
    });

    observer.observe(adRef.current);

    return () => observer.disconnect();
  }, []);

  return <div ref={adRef}>Ad Content Here</div>;
};

  • 애니메이션 동작 여부 결정할 때

요소가 화면에 나타날 때 애니메이션을 시작

=> 사용자의 주의를 끌고, 
웹사이트의 인터랙티브한 요소를 강조
import React, { useEffect, useRef } from 'react';

const AnimatedComponent = () => {
  const animateRef = useRef();

  useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          entry.target.classList.add('start-animation');
          observer.unobserve(entry.target);
        }
      });
    });

    observer.observe(animateRef.current);

    return () => observer.disconnect();
  }, []);

  return <div ref={animateRef}>Animate Me!</div>;
};


@ React-Intersection-Observer

  • React 라이브러리

  • 웹 페이지의 특정 요소가 사용자의 Viewport (화면) 내에
    들어오는지 감지하는 기능 제공

  • 브라우저의 기본 API인 Intersection Observer API를 기반


  • 주요기능

    • 요소의 가시성 감지
    • 무한 스크롤 구현 지원
    • 성능 최적화

  • 설치
npm install react-intersection-observer

  • 사용법
import { useInView } from "react-intersection-observer";

const [ref, inView] = useInView({
   // 옵션 설정 가능
});

  • React 컴포넌트 내에서 특정 DOM 요소의
    가시성(화면에 보이는지 여부)을
    감지하는 데 사용되는 Hook

  • "ref 와 inView" 라는 두 가지 주요한 반환값

    • ref, 감지하고자 하는 DOM 요소에 이 ref를 할당
    • inView, 감시하고 있는 요소가 화면에 보일 때 true
      화면에서 벗어날 때 false
  • 옵션설정

    • threshold
      • 요소의 어느 부분이 뷰포트에 들어와야 inView 가 true가 될지 결정
      • 0에서 1 사이의 값으로 설정 가능
      • 예를 들어 0.5는 요소의 50%가 화면에 들어왔을 때 inView 를 true로 설정

    • triggerOnce
      • 이 옵션을 true로 설정하면,
        요소가 한 번 화면에 나타나고 나면 감지 중지
      • 기본값은 false

    • delay
      • 감지에 딜레이를 추가 가능
      • 요소가 화면에 짧게 나타났다가
        사라지는 경우를 필터링할 때 유용

  • 컴포넌트에 ref 연결
<div ref={ref}>감시할 요소</div>
  • 로직 구현
useEffect(() => {
   if (inView) {
      // 화면에 보이는 경우 실행할 로직
   }
}, [inView])
  • 총 실행 코드
import React, { useEffect } from 'react';
import { useInView } from 'react-intersection-observer';

const ExampleComponent = () => {
  const { ref, inView } = useInView({
    threshold: 0.5, // 화면의 50%가 보일 때 감지
  });

  useEffect(() => {
    if (inView) {
      console.log('요소가 화면에 보입니다!');
    }
  }, [inView]);

  return <div ref={ref}>감시할 요소</div>;
};

export default ExampleComponent;
profile
일단 한다

0개의 댓글