Front-end/React

[React] 디바운싱 적용하여 자동 계산 성능 개선하기

helloyukyung 2023. 3. 21. 00:08

프로젝트에서 견적 요청 값에 따른 자동 계산식을 보여줘야 되는 기능을 만들게 되었다.
사용자가 선택한 여러 옵션값들을 종합하여, 자동으로 계산된 값을 보여줘야 했다.

디바운싱 적용 전

input으로 값을 받을 때, onChange 값이 바뀔 때마다 api를 전송한다면(위 사진 참고) 쓸모없는 api 요청이 발생하여, 웹 성능이 저하될 것이다.

예를 들어 유저가 수량 input에 숫자 100을 입력하려고 할 때, 디바운싱을 적용하지 않는다면

  1. 1
  2. 10
  3. 100

api가 3번이나 호출되고 나서야 원하는 값을 줄 수 있을 것이다.

디바운싱은 연이어 호출되는 함수들 중 마지막 함수만 호출하는 것을 말한다.
나는 특정 서비스 상에 구현되어 자동 계산식이라는 한정된 용어를 사용했지만, 기본적으로 검색 기능을 구현할 때 사용한다고 보면 된다.

디바운싱을 사용하여 위와 같이 3번의 과정을 거쳐 100을 호출하는 것이 아닌, 유저가 값(100)을 입력하고 일정시간 동안 더 이상 값을 입력하지 않을 때 api를 호출하도록 만들어줄 것이다.

useDebounce

import { useEffect, useState } from "react";

function useDebounce<T>(value: T, delay = 500): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);
    return () => {
      clearTimeout(timer);
    };
  }, [value, delay]);
  return debouncedValue;
}

export default useDebounce;

나는 다른 컴포넌트에서 재사용이 가능한 커스텀 훅, useDebounce을 만들어 디바운싱을 구현했다.
useState을 사용하여 디바운스된디바운스 된 값을 저장하고, useEffect을 사용하여 딜레이 시간이 경과했을 때, 입력된 값을 디바운스 된 값으로 업데이트해 준다.
이때, 이전에 실행된 Timer를 제거하기 위해 clearTimeout을 사용해 준다.
setTimeout함수는 타이머 ID를 반환하는데, 이 타이머 ID를 clearTimeout함수로 제거하지 않으면 이전에 생성된 타이머가 계속돼서 실행되기 때문에 메모리 누수(memory leak)가 발생하기 때문이다.

디바운싱 적용 후

마무리하며

평소에 이론적으로만 알던 개념을 실무에서 서비스 내에 실제로 적용하게 되어 뿌듯했다.
단순히 굴러가는 웹 화면을 만드는 것이 아닌 잘 만든 웹사이트를 만들고 싶다는 생각이 더욱더 들게 되었다 :)