설명
Intersection Observer API의 주요 기능은 개발자가 뷰포트에서의 존재 여부에 따라 요소의 "가시성과 모양을 제어" 할 수 있도록 하는 것
"관찰된 요소가 뷰포트에 들어오거나 나가면 API는 콜백을 트리거" 콘텐츠, 애니메이션 또는 작업을 로드하는 데 사용
대표 사용 예시 => "무한 스크롤"
Observer 만들기
대상 요소 관찰
더 많은 콘텐츠 로드
정리
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({
// 옵션 설정 가능
});
"ref 와 inView" 라는 두 가지 주요한 반환값
옵션설정
<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;