[JavaScript] debounce로 스크롤 이벤트 핸들링하기

tamagoyakii·2023년 9월 14일
0

Tamagoyaki Learning

목록 보기
3/3
post-thumbnail

저번에는 throttle을 사용해 클릭 이벤트를 핸들링해봤다. 이번엔 debounce를 사용해볼 차례다.

throttle에 대한 포스팅이 궁금하다면 ~ --> [JavaScript] debounce & throttle

닥터퐁 채팅창은 이벤트 리스너에 등록된 handleScroll 함수에서 useRef의 스크롤 값으로 데이터 요청과 프리뷰 표시 유무를 처리한다. 해당 함수는 다음과 같다.

const chatsRef = useRef(null);

useEffect(() => {
  if (chatsRef.current)
    chatsRef.current.addEventListener('scroll', handleScroll);
  return () => {
    if (chatsRef.current)
      chatsRef.current.removeEventListener('scroll', handleScroll);
  }
}, []);

const handleScroll = () => {
  const ref = chattingsRef.current!;
  if (Math.abs(ref.scrollTop) > ref.scrollHeight - ref.clientHeight - 100) {
    // 스크롤이 맨 위인 경우 다음 페이지의 데이터 요청
  }
  if (ref.scrollTop < -50) {
    // 스크롤이 맨 아래가 아닌 경우 프리뷰 표시
  }
  if (ref.scrollTop > -10) {
    // 스크롤이 맨 아래인 경우 프리뷰 제거
  }
};

return (
  <div ref={chatsRef}>
  </div>
);

이러면 채팅창에서 스크롤을 드르륵~ 할때마다 위의 함수가 미친듯이 호출된다. 모든 스크롤마다 스크롤의 위치를 확인하는 것은 확실히 비효율적인 방법이다. 때문에 debounce를 사용하기로 결정했다. 추가한 debounce 함수는 다음과 같다.

const debouncer = <T extends Function>(func: T, delay: number) => {
  let timer: ReturnType<typeof setTimeout> | null = null;

  return (...args: any[]) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(func, delay, ...args);
  };
};

위의 코드는 이전의 throttle과 다르게 대기시간 중 발생하는 새로운 이벤트를 기준으로 대기시간이 초기화된다. 무슨 말이냐면, delay를 5초로 설정한 함수 A는 5초 동안 새로운 이벤트가 발생하지 않아야 실행된다는 것이다.

위의 함수를 tsx파일에서 import하여 사용했다.

const chatsRef = useRef(null);

useEffect(() => {
  if (chatsRef.current)
    chatsRef.current.addEventListener('scroll', handleScroll);
  return () => {
    if (chatsRef.current)
      chatsRef.current.removeEventListener('scroll', handleScroll);
  }
}, []);

const handleScroll = debouncer(() => {
  const ref = chattingsRef.current!;
  if (Math.abs(ref.scrollTop) > ref.scrollHeight - ref.clientHeight - 100) {
    // 스크롤이 맨 위인 경우 다음 페이지의 데이터 요청
  }
  if (ref.scrollTop < -50) {
    // 스크롤이 맨 아래가 아닌 경우 프리뷰 표시
  }
  if (ref.scrollTop > -10) {
    // 스크롤이 맨 아래인 경우 프리뷰 제거
  }
}, 200);	// 0.2초 동안 스크롤 이벤트가 발생하지 않아야 handleScroll 함수 실행

return (
  <div ref={chatsRef}>
  </div>
);

사실 delay를 조금 더 줄까 생각도 해봤지만, 프리뷰가 보여지는데 문제가 있을 것 같아서 0.2초로 설정했다. 이벤트 핸들링 어렵지 않아요~~!!

0개의 댓글