리팩토링 하는 과정에서 scroll event에 관련된 아주 유용한 api가 있다고 하여 찾아보고 적용해 보았습니다.
브라우저의 뷰포트(상위 요소)와 설정한 요소(대상요소)의 교차점을 비동기적으로 관찰하여 요소가 뷰포트에 포함되는지 안되는지 구별하는 기능을 제공합니다.
const observer: IntersectionObserver = new IntersectionObserver(callback, options)
observer.observe(설정요소)
const observer: IntersectionObserver = new IntersectionObserver((entries, obsercer)=>{}, options)
entries는 IntersectionObserverEntry 인스턴스의 배열이며, 아래와 같은 속성들을 가지고 있습니다.
boundingClientReact: 설정요소의 사각형 정보(DOMReactReadOnly)
intersectionReact: 설정요소의 교차한 영역 정보(DOMReactReadOnly)
intersectionRatio: 설정요소의 교차한 영역 백분율
(intersectionReact영역에서 boundingClientReact 영역까지 비율, number)
isInteresting: 설정요소의 교차 상태(boolean)
rootBounds: 지정한 루트 요소(브라우저의 뷰포트(상위 요소))의 사각형 정보(DOMReactReadOnly)
target: 설정요소(Element)
time: 변경이 발생한 시간정보(DOMHighResTimeStamp)
options 에는 아래와 같은 속성들을 가지고 있습니다.
root: 설정요소의 상위 항목이어야 하고, 설정이 안되어 있으면 기본값은 null로 브라우저 뷰포트입니다.
rootMargin: root의 주변 여백이며, css margin 속성과 유사한 값을 가지고 있습니다.
단위는 px 또는 %로 꼭 입력해야 합니다.
threshold: 설정요소가 어느정도 화면에 보일 때 observer를 실행시킬 지 설정요소 가시성의 백분율을 나타내는 숫자, 숫자배열입니다.
기본값은 0입니다.
설정요소의 관찰을 시작합니다.
const box = document.getElementById("RootBox");
observer.observe(box);
설정요소의 관찰을 중지합니다.
const box = document.getElementById("RootBox");
observer.unobserve(box);
IntersectionObserver 인스턴스가 관찰하는 모든 설정요소의 관찰을 중지합니다.
const box = document.getElementById("RootBox");
observer.disconnect();
const onScroll = React.useCallback(() => {
const Position = document.getElementById("RootBox");
const scrollY = Position?.getBoundingClientRect().bottom;
if (scrollY === undefined) return;
if (scrollY < 0) {
setHeight(true);
} else {
setHeight(false);
}
}, []);
React.useEffect(() => {
//add eventlistener to window
window.addEventListener("scroll", onScroll, { capture: true });
// remove event on unmount to prevent a memory leak with the cleanup
return () => {
window.removeEventListener("scroll", onScroll);
};
}, [onScroll]);
const Positon = document.getElementById("RootBox");
React.useEffect(() => {
if (!Positon) return;
const observer: IntersectionObserver = new IntersectionObserver(([entries]) => {
if (!entries.isIntersecting) {
setHeight(true);
} else {
setHeight(false);
}
});
observer.observe(floorPosition);
}, [Positon, height]);
isIntersecting
의 속성을 통해 조건을 달아서 unobserver를 쓰지 않았습니다.isIntersecting
은 설정요소가 화면에 보이면 true
, 안보이면 false
이기 때문에 안보였을 때에 이벤트가 일어나야 하여, 상기와 같이 조건을 달았습니다.첫번째 박스가 사라지면 나타나는 설정요소!
기존에는 이벤트 핸들러를 통해 스크롤 이벤트를 구현했기때문에 성능이슈 없이 사용 가능합니다.
확실히 코드가 짧아져서 가독성도 좋아졌습니다!
참조 :
Intersection Observer - 요소의 가시성 관찰
Intersection Observer API