JS/React

React - Intersection Observer API

shin96bc 2024. 3. 9. 22:12

 

개요

과거에 교차 감지를 구현하려면 ‘getBoundingClientRect()’ 함수를 사용하여 영향을 받는 모든 요소에 필요한 정보를 구축하는 메서드를 호출하는 이벤트 핸들러 및 루프가 필요했습니다. 그러나 이 모든 코드는 메인 스레드에서 실행되기 때문에 메인 스레드에 과부화가 걸려서 웹 사이트의 성능 자체가 현저히 떨어지는 일들이 많이 발생했습니다.

 

그런 성능저하 문제를 해결하기 위해서 등장한 것이 Intersection Oberver API입니다.

 

https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

 

Intersection Observer API 기본지식

 

Intersection Observer API란 타켓 요소와 상위 요소 또는 최상위 document의 viewport사이의 intersection 내의 변화를 비동기 방식으로 관찰하는 방법을 제공하는 API입니다.

 

Intersection Observer API는 기본적으로 브라우저 Viewport와 Target으로 설정한 요소의 교차점을 관찰하여 그 Target이 Viewport에 포함되는지 구별하는 기능을 제공합니다.

 

예시 사진

 

Intersection Observer Options

root

  • Target의 가시성을 확인할 때 사용되는 상위 속성의 이름입니다.
  • Target 요소가 어디에 들어왔을 때 callback 함수를 실행할지 결정합니다.
  • null을 입력하면 기본값으로 브라우저의 Viewport가 설정됩니다.

 

rootMargin

  • root에 margin값을 주어 범위를 확장할 수 있습니다.
  • 기본갑은 0px 0px 0px 0px이고, 반드시 단위를 입력해야합니다.

 

threshold

  • callback이 실행되기 위해 target의 가시성이 얼마나 필요한지 백분율로 표시합니다.
  • Target 요소가 얼마나 들어왔을 때 callback 함수를 실행할지 결정합니다.
  • 기본값은 배열[0]이며, Number 타입의 단일 값으로도 작성이 가능합니다.(1이면 Target 요소 전체가 들어와야 실행됩니다.)

 

사용법 예시

// import 부분 생략
const App () => {
	// Target으로 사용될 ref
	const targetRef = useRef(null);

	// observer 옵션
	const options: IntersectionObserverInit = {
		threshold: 0.5;
	};

	// observer가 관측되면 실행되는 함수 인자값으로 entries와 observer를 받습니다.
	const callback = (
		entries: IntersectionObserverEntry[],
		observer: IntersectionObserver
	): void => {
		console.log('관측되었습니다. callback 실행');

		// observer는 관측된 IntersectionObserver 객체가 들어옵니다.

		// entries에는 entry 목록들이 들어있습니다.
		entries.forEach((entry: IntersectionObserverEntry) => {
			// entry가 가지고 있는 속성
			// Each entry describes an intersection change for one observed
	    // target element:
	    //   1. entry.boundingClientRect
			//      -> target 요소의 범위 사각형을 DOMRectReadOnly로 반환합니다. 
			//         경계는 Element.getBoundingClientRect() 문서에 설명된 대로 계산됩니다.
	    //   2. entry.intersectionRatio
			//      -> boundingClientRect에 대한 IntersectionRect의 비율을 반환합니다
	    //   3. entry.intersectionRect
			//      -> target의 가시 영역을 나타내는 DOMRectReadOnly를 반환합니다.
	    //   4. entry.isIntersecting
      //      -> target 요소가 교차 관찰자의 루트와 교차하는 경우 true가 됩니다.
			//         true이면 IntersectionObserverEntry는 교차 상태로 전환되었음을 의미합니다. 
			//         false이면 교차 상태에서 교차하지 않은 상태로 전환되었음을 알 수 있습니다.
	    //   5. entry.rootBounds
			//      -> 교차 관찰자의 root에 대한 DOMRectReadOnly를 반환합니다.
	    //   6. entry.target
			//      -> root와의 교차가 변경된 요소입니다.
	    //   7. entry.time
			//      -> IntersectionObserver의 시간 원점을 기준으로 교차가 기록된 시간을 나타내는 DOMHighResTimeStamp입니다.
		});
	};

	// observer 객체 생성
	const observer: IntersectionObserver = new IntersectionObserver(callback, options);

	useEffect(() => {
		if (!targetRef.current) return;
		
		// observe()는 IntersectionObserver 객체에 관찰할 요소를 지정합니다.
		observer.observe(targetRef.current);

		// unobserve()는 IntersectionObserver 객체에 관찰을 중지시킬 요소를 지정합니다.
		observer.unobserve(targetRef.current);

		// disconnect()는 IntersectionObserver 객체의 모든 관찰을 중지시킵니다.
		observer.disconnect();
	}, [targetRef])

	return (
		<div>
			<div>
				...
				리스트
				...
			</div>
			<div ref={targetRef}>target</div>
		</div>
	);
};

export default App;