이 글은 리액트에서 어떻게 Intersection Oberver API를 이용해서 무한 스크롤을 구현하는지에 대해 설명하고있습니다. Intersection Observer API에 대한 자세한 내용은 Intersection Oberver API - WEB API | MDN를 참고해주세요.
React 앱에서 어디서나 사용하기 쉽도록 커스텀 훅을 사용해 기능을 만들어준다.
export default function useIntersectionObserver(callback) {
const observer = useRef(
new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
callback();
}
});
},
{ threshold: 1 }
)
);
const observe = (element) => {
observer.current.observe(element);
};
const unobserve = (element) => {
observer.current.unobserve(element);
};
return [observe, unobserve];
}
useRef를 사용해서 observer 생성한다.
why?
상위 컴포넌트의 생애주기 동안 유지되는 값으로서 사용하기 위한 것이다.
생성 시 파라미터로 받아온 callback도 함께 전달한다.
이제 Observer를 만들었으니 활용해보자.
교차 대상이 감지되면, 새로운 데이터를 불러오도록하는게 목표이다.
이를 위해 다수 개의 데이터, 페이지 그리고 교차 대상이 될 Element가 필요하다.
최종 구현을 위해 필요한 기능들을 쪼개나가면서 차근차근 살펴보자!
리스트의 끝에 다다랐을 때 새로운 데이터를 가져와야한다.
이를 위해 리스트 컴포넌트 바로 아래에 교차 대상을 위치시키자.
const target = useRef(null);
return (
<div>
<DataList dataList={data.result} /> // 데이터를 그려낼 컴포넌트
<div ref={target} style={{ width: '100%', height: 30 }} />
</div>
);
교차가됐을 때 해야할 일을 등록해준다.
지금 상황에서는 새로운 데이터 가져오기가 할 일이므로 page상태를 1 늘려준 값으로 변경한다.
const [observe, unobserve] = useIntersectionObserver(() => {
setPage((page) => page + 1);
});
구현을 위해 필요한 값들의 준비는 끝이났다. 본인이 사용할 데이터에 대한 상태정의도 함께 해두자.
위에서 정의한 타겟 요소를 Observer가 관찰할 수 있도록 등록해줘야한다. 또한, 무한하게 교차가 되는 것을 막기 위해 등록을 해제해야한다.
useEffect(() => {
if (page === 1) observe(target.current);
const N = data.result.length;
const totalCount = data.totalCount;
if (0 === N || totalCount <= N) {
unobserve(target.current);
}
}, [data]);
코드가 약간 복잡해보일 수 있지만 어렵지 않다. 질문에 대한 답을 해가면서 이해해보자.
observe는 언제 호출하면 될까?
첫 데이터가 도착한 후, page가 1일 때 호출하면 될 것이다.
unobserve는 언제 호출하면 될까?
서버에 있는 모든 데이터가 도착했을 때다. (이를 위해 totalCount와 같이 전체 데이터 개수에 대한 정보를 알고있어야 된다)
마지막으로, 페이지가 증가했다면 새로운 데이터를 불러와 상태를 업데이트하는 함수를 호출한다.
useEffect(() => {
updateData(page);
}, [page]);
기본적인 구현은 끝이났다. 👏
하지만, 실제 서비스에 적용하기에는 에러사항이 존재한다.
쓸만한 기능으로 만들기위해 어떤 이슈가있는지 살펴보고 코드를 개선해보자.
실제 서비스에서 응답을 받기까지 1초가 걸릴 수도 또는 그 이상이 걸릴 수도 있다.
이런 상황에서 응답을 받아오는 도중에도 교차가 여러 번 일어날 수 있다. 따라서 요청 또한 여러 번 발생할 것이다.
데이터를 가져오는 도중(로딩 중)에는 교차가 발생하지 않도록하면 될 것이다.
로딩 상태를 알기 위해 isLoading 상태를 추가해주었고, 통신 전 후로 isLoading 상태를 업데이트해주자.
이 상태를 이용해 로딩 중일 때는 교차 대상을 unobserve하도록 해주고 로딩이 끝이나면 다시 observe하도록 하자.
useEffect(() => {
if (isLoading) {
unobserve(target.current);
} else {
observe(target.current);
}
}, [isLoading]);
이상으로 React + Intersection Observer API를 이용해 무한 스크롤 구현하기 포스팅을 마무리하겠다.
안녕하세요, 리액트 공부하면서 무한스크롤을 구현해보고 싶어서 찾다가 포스트 확인하고 구현에 성공했습니다! 좋은 글 감사합니다~ ^^