개요
안녕하세요. 웹 프론트엔드 개발자 설탕시럽입니다. 이번 글에서는 Intersection Observer를 활용하여, 사용자의 화면을 기준으로 컴포넌트에 변화를 주는 방법에 대해 소개해드리려고 합니다. scrollEvent를 활용한 방식이 아닌 Intersection Observer를 활용하여, 스크롤이 기준이 아닌 유저가 보는 화면을 기준으로 UI를 수정할 수 있는 방식입니다.
요구사항
- 여러개의 아티클 Item이 세로 스크롤로 나열되어 있습니다.
- 유저에게 잡히는 메인 Item은 투명도 조절 없이, 그 외 Item은 불투명하게 화면에 표현하여 메인 아티클을 강요합니다.
위와 같은 요구사항을 만족시키기 위한 방법으로 Lazy Loading에 많이 활용되는 Intersection Observer를 활용하면 좋을 것 같다고 생각했습니다. Lazy Loading을 구현할 때에도 개발자가 영역을 지정하여, 해당 영역이 사용자 화면에 얼마나 보이면 load 하는데, 이를 사용자의 viewport를 기준으로 Item의 투명도를 자연스럽게 조절할 수 있지 않을까? 해서 Intersection Observer를 선정하고 구현하게 되었습니다.
Intersection Observer
Intersection Observer는 대상 요소와 viewport 교차점의 변경 사항을 비동기 적으로 관찰하는 방법을 제공합니다. Intersection Observer의 기본 문법은 다음과 같습니다.
let observer = new IntersectionObserver(callback, options);
observer.observe(target)
- callback : 생성자를 호출하고, 특정 조건마다 실행될 콜백 함수
- options : 해당 arguments를 통해 callback이 호출되는 상황을 제어
여기서 우선적으로 설정한 부분은 options입니다. target으로 지정한 요소가 viewport에 몇% 보일 때마다 callback함수를 호출하여 target의 opacity를 수정한다면 opacity의 변화를 부드럽게 구현할 수 있다고 생각했습니다. 생각대로 구현하기 위해 options의 threshold 옵션을 활용했습니다.
let observer = new IntersectionObserver(callback, {
threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
});
observer.observe(target)
- threshold : observer가 실행되기 위해, target이 얼마나 보여야 하는지를 표시합니다. ( ex. 0 -> 타겟의 가장자리가 가시 되는 순간)
- 이를 배열로 저장하면 배열 내, 가시성에 대해 모두 observer가 실행되며 callback 함수가 동작 합니다.
options 뿐 아니라, 몇 %가 화면에 보이는지에 대한 data도 필요합니다. target이 얼마나 보이는 지 알아야 opacity를 설정할 수 있기 때문이고 해당 값을 가져오기 위해 callback함수의 argument entry의 intersectionRatio 속성을 활용하여 데이터를 가져올 수 있습니다.
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
console.log(entry.intersectionRatio);
})
}, {
threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
});
observer.observe(target);
이렇게 Intersection Observer를 활용하여 사용자의 viewport 기준으로 요소의 상태를 수정할 준비는 완료되었습니다. 실제 제가 작성한 jsx는 다음과 같습니다.
예제 코드
function IntersectionObserverItem() {
const ContainerRef = useRef<HTMLDivElement>(null);
const [opacity, setOpacity] = useState(0.3);
useEffect(() => {
if(!ContainerRef.current) return;
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
let entryIntersectionRatio = Math.floor(entry.intersectionRatio * 100 ) / 100;
if(entryIntersectionRatio >= 0.65) {
setOpacity(1);
} else if(entryIntersectionRatio <= 0.35) {
setOpacity(0.3);
} else {
setOpacity(entryIntersectionRatio);
}
})
}, {
threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
});
observer.observe(ContainerRef.current);
});
return (
<... ref={ContainerRef}>
...
</ ...>
)
}
export default IntersectionObserverItem;
- 실제 코드에서는 보다 부드럽게 하기 위해 threshold 배열을 더 디테일하게 넣었습니다
마무리하며...
이렇게 Intersection Observer를 활용하여 사용자의 viewport에 맞게 변화하는 컴포넌트를 구현했고, 예제를 소개드렸습니다. 이전까지 Intersection Observer는 Lazy loading처럼 scroll에 따른 data를 동적으로 불러오는 정도로 활용하는 데 그쳤으나, 이번 방법을 고민해 보면서 더 유용하게 활용할 수 있는 여지가 많은 객체라는 생각을 해보게 되었습니다.
저는 요구사항에 맞게 opacity를 조정하는 데 사용했지만, 더 다양하게 활용될 여지가 있다고 생각하고 조금이라도 Intersection Observer를 활용하는데 도움이 되는 게시글이었기를 바랍니다
'React' 카테고리의 다른 글
[AWS] Sub Domain 연결하기 (5) | 2024.10.31 |
---|---|
[React + Vite + Nginx + Docker + AWS] 를 활용하여 배포 해봅시다! (0) | 2024.06.05 |
useState 딥다이브 (0) | 2023.06.04 |
JSX (0) | 2023.05.17 |
React의 특징과 장점, 적용 예제 까지! (0) | 2023.05.16 |