클론코딩의 필수 덕목 infinite scroll이다.
원리를 설명하자면, react에서 dom을 접근할 수 있는 거의 유일한 요소인 ref를 활용하여 해당 element가 화면에 보인다면 특정 콜백함수를 실행시킴으로서 새로운 데이터를 fetch하는 것이다. 바로 코드로 넘어가자
const [target, setTarget] = useState<any>(null);
useEffect(() => {
const observer = new IntersectionObserver(callBackFunction, options);
const currentTarget = target;
if (currentTarget) observer.observe(currentTarget);
return return () => observer && observer.disconnect();
}, [target, options]);
저게 무슨 코드인가요? 컴포넌트가 mount될 때 observer 를 IntersectionObserver의 새로운 객체로 생성한다.
매개변수는 두개인데 callBackFunction은 요약하자면 특정 element(인스타라고 가정한다면 맨 마지막 리스트 되시겠다.)가 화면에 보이면 실행시킬 콜백 함수 이고 option은 얼마만큼 보여야하고, 얼마만큼의 노출이 있어야지 화면에 표시 됐다고 인식할래? 를 정하는 파라미터이다. 노출시켜야할 element는 다음과 같다.
<div ref={setTarget}></div>
target이 null이 아닐경우, observer는 observe 프로토타입 함수를 이용하여 해당 타겟의 엘리먼트를 관찰하기 시작한다. 아까 언급했듯이 얼마나 노출됐을 때 관찰됐다고 정의할래? options는 다음과 같다.
const options = useMemo(() => {
return {
root: null,
rootMargin: "0px",
threshold: 0.5,
};
}, []);
변하지 않으므로 useMemo로 한번만 생성시켜 주자
우리가 알아야 할 것은 threshold인데, 0.5는 50프로가 노출됐을 때 관찰됐다고 취급해주세요 라는 의미이다. 그럼 관찰 됐을 때 실행할 함수는?
const callBackFunction = async (entries: any, observer: any) => {
const [entry] = entries;
if (entry.isIntersecting) {
observer.unobserve(entry.target);
await new Promise<void>((resolve, reject) => {
return setTimeout(resolve, 2000);
});
setPage(page + 1);
observer.observe(entry.target);
}
};
관찰된 순간에 수백번의 함수실행을 막기 위해 2초의 텀을 두었다. 관찰을 중지한 후 페이지를 +1 한 후 다시 새로운 타겟을 관찰한다,
정리해보자.
1.currentTarget 이 null이 아니라면 해당 element를 관찰( observer.observe(currentTarget);)
2.관찰 됐다면 callBackFunction 실행! (추후에 외부에서 데이터를 받아와 추가하면 되겠다.)
3.cleanUp function ( return () => {
if (currentTarget) observer.unobserve(currentTarget);
};) 으로 unmount된다면 관찰을 포기시켜준다.
끗!