[React] Debouce & Throttle

박하늘·2025년 3월 14일

React

목록 보기
15/15

Debouce & Throttle

사용자의 입력이나 이벤트 발생 빈도를 제어하여 성능을 최적화하는 기법
연속적으로 발생하는 함수나 이벤트를 묶어서 처리하는 방식

  • 검색창 자동완성: 사용자가 입력할 때마다 API 요청을 보내면 성능이 저하됨 → Debounce 사용
  • 스크롤 이벤트 최적화: 스크롤할 때마다 매번 함수가 실행되면 성능 저하 → Throttle 사용

[연속적인 작업]

[끊기는 작업]

1️⃣ Debounce(디바운스)

연속된 이벤트 중 마지막 이벤트가 발생한 후 일정 시간이 지나야 실행됨
마지막에 한 번에 묶어서 처리해도 상관 없을 때
ex) 검색창 자동 완성

▪️ 사용 예시

  • 사용자가 검색창에 입력할 때 입력이 끝난 후에만 API 요청
  • 버튼 클릭을 여러 번 해도 마지막 클릭 후 일정 시간 후 실행
function Search () {
    const [searchParams] = useSearchParams()
    const [filteredData, setFilteredData] = useState(data)
    const param = searchParams.get('animal')
    const reg = getRegExp(param)

    // 📍 Debounce 사용 !!
    
    // param(검색어)이 변경될 때마다 useEffect가 실행됨.
    useEffect(() => {
        // setTimeout을 사용하여 1초(1000ms) 뒤에 data.filter(...)를 실행.
        const debounceTimer = setTimeout (() => {
        	const newFilteredData = data.filter ((el) => el.name.match(reg))
      		setFilteredData(newFilteredData);
      		}, 1000);
        return () => clearTimeout(debounceTimer);
      	// 하지만 param이 변경되면 useEffect가 다시 실행되면서 기존 setTimeout이 clearTimeout을 통해 취소됨.
        }, [param]);

    return (
        <>
        <ul>
        {filteredData.map((el) => (<li key={el.id}>
            <Link to={`/detail/${el.id}`}>
            <img src={el.img}></img>
            <div>{el.name}</div>
            </Link>
        </li>))}
    </ul>
        </>
    )
}
  • 즉, 사용자가 연속으로 입력할 경우, 입력이 멈춘 후 1초 뒤에만 filteredData가 업데이트됨.
  • 사용자가 검색어를 입력할 때마다 API 요청 또는 필터링 로직이 실행되지 않음.
  • 마지막 입력 후 1초가 지나야만 filteredData가 변경됨.
  • 불필요한 연산을 줄일 수 있음.

2️⃣ Throttle(쓰로틀)

일정 시간 간격마다 최대 한 번만 실행됨
Throttle 중간 중간 끊기지 않는 인터랙션이 필요할 때
ex) 마우스 이동, 스크롤 이벤트

▪️ 사용 예시

  • 스크롤 이벤트 최적화 (스크롤 시 일정 간격으로 이벤트 실행)
  • 버튼 연타 방지 (클릭 후 일정 시간 동안 추가 실행 방지)
function Search () {
    const [searchParams] = useSearchParams()
    const [filteredData, setFilteredData] = useState(data)
    const param = searchParams.get('animal')
    const reg = getRegExp(param)
    // time.current(이전 실행 시간)를 저장.
    const time = useRef(new Date())

    // 📍 Throttle 사용 !!
    useEffect (() => {
        const newTime = new Date();
        const throttleTimter = setTimeout (() => {
        const newFilteredData = data. filter((el) => el. name.match (reg));
        setFilteredData (newFilteredData);
        // setTimeout이 실행되면 filteredData를 업데이트하고, time.current를 최신 실행 시간으로 갱신.
        time. current = new Date ();
          // 즉, 마지막 실행 후 1초가 지나지 않았다면, 남은 시간만큼 대기 후 실행.
        }, 1000 - (newTime - time.current));
        return () => clearTimeout (throttleTimter);
        }, [param]);

    return (
        <>
        <ul>
        {filteredData.map((el) => (<li key={el.id}>
            <Link to={`/detail/${el.id}`}>
            <img src={el.img}></img>
            <div>{el.name}</div>
            </Link>
        </li>))}
    </ul>
        </>
    )
}

export default Search;
  • param이 자주 변경되어도, 최소 1초 간격으로만 filteredData가 업데이트됨.
  • 불필요한 연산을 막을 수 있음.
  • 하지만 사용자가 검색어를 입력할 때마다 filteredData가 변경될 수 있음 (Debounce와 차이점).



3️⃣ Debouce & Throttle 차이점

비교 항목DebounceThrottle
실행 조건마지막 이벤트 발생 후 일정 시간 대기이벤트 발생 후 일정 시간마다 실행
주요 특징  연속 입력 시 실행 취소 후 다시 대기일정 간격으로 실행
사용 사례     검색 입력창, 자동 저장 기능무한 스크롤, 버튼 클릭 제한
UX 차이   검색이 끝난 후에 실행 됨 (지연)중간중간 실행됨

🔹 결론

•	1번(Debounce)은 검색 필터링 같은 경우에 적합 (입력이 끝난 후 실행).
•	2번(Throttle)은 스크롤 감지나 주기적인 실행이 필요한 경우 적합 (1초마다 실행).

0개의 댓글