최근 무한 스크롤 구현을 하다가 scroll이벤트보다 좋은 방법으로 무한 스크롤 구현을 알아보다 Intersection Observer API를 알게되었고 제가 한번 해보도록 하겠습니다!
yarn add react-intersection-observer
또는
npm i react-intersection-observer
Intersection Observer 예제
let observer = new IntersectionObserver(callback, options);
Intersection Observer를 생성할 때는 3가지 옵션 설정이 가능하다.
옵션에는 root, rootMargin, threshold 이 있다.
우선 Style 부분의 설명은 제외하고 설명을 하겠습니다.
전체코드
const InfiniteScroll = () => {
const [itemList, setItemList] = useState<number[]>([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
]);
const [target, setTarget] = useState<HTMLElement | null | undefined>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const onIntersect: IntersectionObserverCallback = async (
[entry],
observer,
) => {
if (entry.isIntersecting && !isLoading) {
//관찰대상 끊기
observer.unobserve(entry.target);
//로딩컴포넌트 on
setIsLoading(true);
// 데이터를 가져오는 부분
await new Promise((resolve) => setTimeout(resolve, 1000));
let Items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
setItemList((itemLists) => itemLists.concat(Items));
setIsLoading(false);
//새로운 관찰대상 target
observer.observe(entry.target);
}
};
return (
<>
<ItemWrap>
{itemList.map((item: number, index: number) => {
return <Styled.Item>{index + 1}</Styled.Item>;
})}
</ItemWrap>
{isLoading ? (
<LoaderWrap>
<ReactLoading type="spin" color="#A593E0" />
</LoaderWrap>
) : (
''
)}
<div ref={setTarget} />
</>
);
};
useEffect(() => {
if (!target) return;
let observer: IntersectionObserver;
if (target) {
observer = new IntersectionObserver(onIntersect, {
threshold: 0.4,//margin이라고 생각하면 편합니다.
});
observer.observe(target);
}
return () => observer && observer.disconnect();
}, [target]);
return (
<>
<ItemWrap>
//이미지 렌더링
{itemList.map((item: number, index: number) => {
return <Item>{index + 1}</Item>;
})}
</ItemWrap>
//로딩시 보이는 컴포넌트
{isLoading ? (
<LoaderWrap>
<ReactLoading type="spin" color="#A593E0" />
</LoaderWrap>
) : (
''
)}
//감시하는곳
<div ref={setTarget} />
</>
);
};
생각보다 개념이 어렵게 느껴져서 애먹은거 같은데 막상 구현하고 보니 이해가 되었던거 같다. 이런식으로 웹 성능과 관련된 것들을 더 공부해 나아 가야 겠다.