-
[무한스크롤]IntersectionObserverReact 2023. 11. 2. 17:25
무한 스크롤 구현을 위해서 자주 사용되는 IntersectionObserver에 대해서 기본적인 내용 정리
1.옵저버 객체 생성 [new IntersectionObserver]
const io = new IntersectionObserver(observerCallback[,options])
2.수행할 동작[observerCallback]
대상을 감지하면 실행하는 함수로 entries와 observer를 받는다.
- entries
IntersectionObserverEntry 인스턴스를 담은 배열 객체로 가시성과 관련된 속성을 포함한다. - observer
observerCallback가 호출되는 InterSectionObserver를 가리킨다.
const observerCallback = (entries, observer) => { entries.forEach(entry => { // entry.boundingClientRect // entry.intersectionRatio // entry.intersectionRect // entry.isIntersecting // entry.rootBounds // entry.target // entry.time });
entries 속성 설명
entry.boundingClientRect 관찰 대상의 경계 사각형을 DOMReactReadOnly로 반환
getBoundingClientRect() 과는 다르게 reflow를 발생시키지는 않는다.entry.intersectionRect 관찰 대상의 교차한 영역 정보를 반환 entry.intersectionRatio 관찰 대상의 intersectionRect와 boundingClientRect가 어느정도로 겹쳐졌는지
비율(0.0~1.0)로 반환 즉 타겟 요소가 루트 요소와 얼마나 교차하는지를 나타낸다.entry.isintersecting 관찰 대상이 교차 상태인지(true) 아닌지(false) Boolean값으로 반환 entry.rootBounds 지정한 루트 요소의 사각형 정보를 반환 entry.time 교차상태 변경이 발생한 시간 정보 반환 ⚠️교차 상태라는건 root요소에 target이 겹쳐있는지 아닌지를 의미한다.
observer 메서드
Observer.observe(targetElement) 타겟 요소에 대한 관찰을 시작한다. Observer.unobserve(targetElement) 타겟 요소에 대한 관찰을 중지한다. Observer.disconnect() 인스턴스의 타겟 요소들에 대한 모든 관찰을 중지 Observer.takerecords(targetElement) IntersectionObserverEntry인스턴스들의 배열을 리턴 3.루트요소의 설정[Options]
const options = { root : viewport, rootMargin : 0 threshold : 0, }
옵션을 설정하지 않으면 기본값으로 들어간다.
- root
타겟 요소의 가시성을 확인할 때 사용되는 루트요소 기본값은 뷰포트이다.
observe의 대상으로 등록할 엘리먼트는 반드시 root의 하위 엘리먼트여야 한다. - rootMargin
root요소의 margin값을 지정한다. 기본값은 0으로 px,%로 표현 가능하다. - threshold
callback이 실행될 타겟 요소의 가시성이 얼마나 필요한지 나타내는 값이다.숫자,숫자 배열로 나타낼 수 있다.
0 : 타겟이 Root요소에 나타나는 순간 바로 콜백 실행
0.5: 타겟의 가시성이 50% 즉 반만 보였을 때 콜백 실행
[0,0.25,0.5,0.75,1] : 25%의 단위로 가시성이 변경될 때 마다 콜백이 실행
4.리액트에서 훅으로 사용하기
https://usehooks-ts.com/react-hook/use-intersection-observer
//useInterserctionObserver.ts import { RefObject, useEffect, useState } from "react"; function useIntersectionObserver( elementRef: RefObject<Element>, { threshold = 0.1, root = null, rootMargin = "0%" } ) { const [entry, setEntry] = useState<IntersectionObserverEntry>(); const updateEntry = ([entry]: IntersectionObserverEntry[]): void => { //intersectionObserverEntry 인스턴스를 담은 배열을 entry상태에 담아준다. setEntry(entry); }; useEffect(() => { const node = elementRef?.current; //관찰 해야할 target const hasIOSupport = !!window.IntersectionObserver; //브라우저가 지원하는지 확인 if (!node || !hasIOSupport) return; const observerParams = { threshold, root, rootMargin }; const observer = new IntersectionObserver(updateEntry, observerParams); //observer를 생성했으므로, observe메서드를 통해서 target을 감시(target:페이지 맨 하단에 있는 div) observer.observe(node); return () => observer.disconnect(); //클린업 함수-언마운트되면 감시를 멈추도록한다. // eslint-disable-next-line react-hooks/exhaustive-deps }, [elementRef?.current, root, rootMargin, JSON.stringify(threshold)]); return entry; } export default useIntersectionObserver;
//감시가 필요한 객체가 있는 컴포넌트 export default function PostList(){ const ref = useRef<HTMLDivElement | null>(null); //타겟을 지정하기 위한 useRef const pageRef = useIntersectionObserver(ref, {}); //io훅을 통해서 entry를 받아온다. const isPageEnd = !!pageRef?.isIntersecting; // 페이지의 끝인지 확인 - inintersecting:교차상태인지 아닌지 Boolean값으로 반환해줌 console.log(isPageEnd) //페이지가 맨끝에 도달했는지 확인 가능 return{ ... <div ref={ref} /> //페이지 최하단에 있는 target엘리먼트 } }
'React' 카테고리의 다른 글
브라우저의 렌더링 (+가상DOM) (0) 2023.11.30 [Recoil]리코일 사용하기 (0) 2023.11.07 [Hooks]useReducer (0) 2023.06.19 [Hooks]useEffect (0) 2023.06.19 [Redux기초]Redux 사용하기 (0) 2023.04.17 - entries