인피니티 스크롤(Infinity Scroll) (2. onScroll)

eeensu·2023년 8월 15일
0

React 실무

목록 보기
3/22
post-thumbnail

일반적인 스크롤 방식으로 하는 인피니티 스크롤 방법은 엘리먼트의 scrollHeight, clientHeight, offsetHeight, scrollTop을 활용하여 이벤트를 처리한다.

  • scrollHeight
    엘리먼트의 총 높이를 나타내며 바깥으로 넘쳐서 보이지 않는 콘텐츠도 포함한다.

  • clientHeight
    엘리먼트의 내부 높이를 나타낸다. padding, scroll bar 높이, margin, border를 포함하지 않는다.

  • offsetHeight
    padding포함, scroll bar 높이, margin, border를 포함한 높이이다.

  • scrollTop
    스크롤바의 top 부분이 화면에 내려온 위치

즉, const height = scrollHeight - clientHeight - scrollTop 이 미리 정해놓은 offset 미만일 때 스크롤이 최하단에 왔다고 판단해서 다음 데이터를 가져오고 기존 항목에 덧붙인다. 보통 offset의 크기는 50내외를 적용한다.




스크롤 방식의 한계

스크롤을 움직일 때마다 이벤트가 발생하기 때문에 성능 문제가 야기될 수 있다. 이를 해결하기 위해 보통 스크롤 이벤트에 쓰로틀링(throttling) 혹은 디바운싱(debouncing)을 적용하여 이벤트를 제한한다. 주로 사용하는 방법은 쓰로틀링이다.



Throttling

이벤트를 일정한 주기마다 발생하는 기술이다. 마지막 함수가 호출된 후 일정 시간이 지나기 전엔 다시 호출되지 않도록 한다.

Debounce

debounce는 이벤트를 그룹핑해서 특정 시간이 지난 후 하나의 이벤트만 발생하도록 하는 기술이다. 연달아서 호출되는 함수들 중 마지막 함수만 호출하도록 한다.

const refUl = useRef<HTMLUListElement | null>(null);
const curPageRef = useRef<number>(0);
const [isScrollBottom, setIsScrollBottom] = useState<boolean>(false); 
.
.
.
// scroll 이벤트에 적용할 함수. refUl 엘리먼트의 ref를 가져와 인피니티 스크롤에 필요한 높이 값들을 가져옴.
// 이후 throttle 효과로 1초 주기마다 발생하도록 작동
const handleScroll = throttle(1000, () => {
  if (refUl.current) {
    const { scrollHeight, offsetHeight, scrollTop } = refUl.current;
    const offset = 50;

    setIsScrollBottom(scrollHeight - offsetHeight - scrollTop < offset);
  }
});

.
.
.

// isScrollBottom이 될 때마다 useEffect()호출, 현재 페이지 수 증가, 
// 마지막 데이터가 아닐 경우에만 fetch 호츌
useEffect(() => {
  if (isScrollBottom) {
    curPageRef.current = curPageRef.current + 1;
    !isLast && getFetchData();           
  }
}, [isScrollBottom, isLast]);

.
.
.

// 페이지의 기본 이벤트에 있는 onScroll에 함수를 넣어주어 스크롤 이벤트가 발생하면 호출되도록 함
return (
  <ul ref={refUl} onScroll={handleScroll}>         
    {
   		// fetch해온 데이터 로직 작성...
    }
  </ul>
);
profile
안녕하세요! 26살 프론트엔드 개발자입니다! (2024/03 ~)

0개의 댓글