Published On

Debounce와 Throttle의 차이점 및 활용법


웹 애플리케이션에서 이벤트가 너무 자주 발생하는 것을 방지하기 위해 DebounceThrottle를 자주 사용합니다.

이 두 가지는 비슷해 보이지만 작동 방식과 목적에 차이가 있습니다.

이 글에서는 각각의 정의와 차이점, 사용 예제, 그리고 React에서의 활용 및 구현 방법에 대해 알아보겠습니다.


Debounce와 Throttle의 차이점

항목DebounceThrottle
동작 방식마지막 이벤트 이후 일정 시간 대기 후 실행일정한 주기마다 한 번씩 실행
주요 목적이벤트의 과도한 호출을 방지자주 발생하는 이벤트를 일정 주기로 제한
사용 예시검색어 자동완성, 버튼 중복 클릭 방지스크롤 이벤트, 윈도우 리사이즈 이벤트

Debounce란?

Debounce는 연속된 이벤트가 발생할 때, 일정 시간 동안 추가 입력이 없을 경우에만 마지막 이벤트를 실행하는 기법입니다. 사용자가 짧은 시간 안에 여러 번 버튼을 클릭하거나 입력 필드를 수정하는 경우, 불필요한 이벤트 호출을 줄이기 위해 유용합니다.

Debounce 사용 예시:

  • 검색 자동완성: 사용자가 검색어를 입력할 때마다 API 요청을 보내는 대신, 입력이 끝나고 일정 시간 동안 멈췄을 때만 API 요청을 보냅니다.
  • 버튼 클릭 방지: 사용자가 같은 버튼을 빠르게 여러 번 누르는 것을 막아주는 기능입니다.

Throttle란?

Throttle는 연속된 이벤트가 발생해도 일정한 주기마다 한 번만 이벤트를 실행하는 기법입니다. 스크롤 이벤트나 윈도우 크기 조정과 같이 자주 발생하는 이벤트에서 성능 최적화를 위해 주로 사용됩니다.

Throttle 사용 예시:

  • 스크롤 이벤트 처리: 사용자가 페이지를 스크롤할 때 일정 시간 간격으로만 이벤트를 처리합니다.
  • 윈도우 리사이즈 이벤트: 창 크기 조정 중 이벤트가 너무 자주 발생하지 않도록 제한합니다.

코드 구현

이 글에서는 throttleHelper와 같은 일반적인 구현 방식이 아닌 React를 활용한 훅 방식으로 구현하였습니다.

utils.tsjavascript
import { useState, useEffect, useRef } from "react";

// Debounce Hook 구현
export const useDebounce = <T,>(value: T, delay: number = 500): T => {
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay);
    return () => clearTimeout(timer); // 타이머 해제
  }, [value, delay]);

  return debouncedValue;
};

// Throttle Hook 구현
export const useThrottle = <T,>(value: T, delay: number = 500): T => {
  const [throttledValue, setThrottledValue] = useState<T>(value);
  const lastRan = useRef<number>(Date.now()); // 마지막 실행 시간 저장

  useEffect(() => {
    const handler = setTimeout(() => {
      if (Date.now() - lastRan.current >= delay) {
        setThrottledValue(value);
        lastRan.current = Date.now();
      }
    }, delay - (Date.now() - lastRan.current));

    return () => clearTimeout(handler); // 타이머 해제
  }, [value, delay]);

  return throttledValue;
};

debounce 사용 예제

import { useState, useEffect, ChangeEvent } from "react";
import { useDebounce } from "./utils"; // Debounce Hook 임포트

export default function SimpleDebounceExample() {
  const [inputValue, setInputValue] = useState < string > ""; // 입력 값 상태
  const debouncedValue = useDebounce < string > (inputValue, 500); // Debounce된 값 생성

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setInputValue(e.target.value); // 입력 값 업데이트
  };

  // debouncedValue가 변경될 때 콘솔에 로그 출력
  useEffect(() => {
    console.log(`Debounced Value: ${debouncedValue}`);
  }, [debouncedValue]);

  return (
    <div style={{ padding: "20px" }}>
      <h1>간단한 Debounce 예제</h1>

      <div style={{ marginBottom: "20px" }}>
        <label htmlFor="search">텍스트 입력:</label>
        <input
          id="search"
          type="text"
          value={inputValue}
          onChange={handleChange}
          placeholder="Type something..."
        />
      </div>

      <div>
        <p>Debounced Value: {debouncedValue}</p>
      </div>
    </div>
  );
}

throttle 사용 예제

import { useState, useEffect } from "react";
import { useThrottle } from "./utils"; // Throttle Hook 임포트

export default function ScrollThrottleExample() {
  const [scrollPosition, setScrollPosition] = useState < number > 0; // 스크롤 위치 상태

  // Throttled 스크롤 핸들러 정의
  const throttledScrollPosition = useThrottle < number > (scrollPosition, 1000); // 1초마다 업데이트

  useEffect(() => {
    const handleScroll = () => {
      setScrollPosition(window.scrollY); // 현재 스크롤 위치 업데이트
    };

    window.addEventListener("scroll", handleScroll); // 스크롤 이벤트 리스너 등록
    return () => window.removeEventListener("scroll", handleScroll); // 언마운트 시 이벤트 리스너 해제
  }, []);

  return (
    <div style={{ height: "200vh", padding: "20px" }}>
      <h1>Throttle을 사용한 스크롤 이벤트 예제</h1>
      <p>현재 스크롤 위치: {throttledScrollPosition}px</p>
    </div>
  );
}

일반 함수(throttleHelper)와 훅(useThrottle)의 차이점과 장단점

throttleHelper와 같은 일반적인 구현 방식과 useThrottle과 같은 React 훅 방식은 사용 목적과 상황에 따라 각각의 장단점이 있습니다.

항목일반 함수 (throttleHelper / debounceHelper)React 훅 (useThrottle / useDebounce)
사용 환경React 외부나 다른 라이브러리에서도 사용 가능React 컴포넌트 내부에서만 사용 가능
코드 복잡성단순하고 짧은 코드로 구현 가능훅과 상태 관리를 포함해 다소 복잡함
상태 관리상태 관리와 연계 어려움React 상태와 자연스럽게 통합 가능
생명주기 제어생명주기 제어가 불가능useEffect로 생명주기 제어 가능
메모이제이션직접 메모이제이션 관리 필요useCallback, useRef 등을 활용한 최적화 가능
재사용성프레임워크 독립적으로 사용 가능React 프로젝트 내에서만 사용 가능