개발일기/Web

[React] 검색 요청 최적화하기 with Debounce

DongKeun2 2023. 8. 25. 15:06
검색 기능을 구현하다보면 다양한 검색 방식을 사용할 수 있습니다.
그 중 검색 버튼, 엔터 키 등 트리거가 명확한 경우도 있지만, 입력을 마친 시점에 자동으로 검색이 진행되는 경우를 원할 수도 있습니다. 이때 입력할 때마다 검색이 된다면 원치 않는 검색어로 검색을 시도하기 때문에 쿼리 낭비가 심해질 수 있습니다.
이를 개선하기 위해 Debounce를 활용합니다. 

Input 입력

여기 단순한 Input이 있습니다.

해당 컴포넌트는 다음과 같이 Input 값이 변경될 때마다 onChange함수를 실행합니다.

onChange함수는 상위 컴포넌트에서 검색을 요청할 때 사용합니다.

이렇게 구현한다면 입력할 때마다 검색을 실행할 수는 있습니다.

만약 토피넛라떼를 검색하고 싶어 입력을 했다 생각해보겠습니다.

이 경우 제가 원하는 검색은 입력을 마친 후 '토피넛라떼' 한 번이지만, 실제로는 다음과 같습니다.

마지막 두 개의 요청은 브라우저의 고유 이벤트로 인해 onChange가 한 번 더 불리게 되어 state 감지가 반복되는 현상으로 isComposing을 통해 조합문자인지 판별하여 예외처리를 해주면 됩니다. 입력하는 중에는 조합 문자로 판단하기 때문에 true일 때만 상태를 변경하면 됩니다.

(react 공식문서에서 브라우저 고유 이벤트 핸들링을 원하면 nativeEvent 속성 사용을 안내하고 있따. 사실 본문과 상관없지만 궁금해서 찾아봤다.)

이렇게 handleChange 함수를 수정하면 원하는 대로 입력한 값만 onChange를 통해 반영됩니다.

(해당 부분은 debounce처리를 할 경우 사용할 필요가 없습니다. 또한 백 스페이스로 단어를 지울때에는 인풋의 값을 조합문자로 판별하지 않기 때문에 원하는 동작을 수행하기 위해서는 다른 방법을 사용하는 게 좋습니다.)

 

하지만 이렇게 하더라도 결국 불필요한 요청이 10번 이상 발생하기 때문에 이 방법도 효율적이지 못합니다.

 

그렇기 때문에 호출을 미뤄주는 Debounce를 적용해야 합니다.

 

Debounce ?

  • 디바운싱(Debouncing)은 불필요한 작업을 반복하지 않도록 적용하는 프로그래밍 방법입니다.
  • 함수를 여러 번 호출하게 되는 경우, 가장 마지막에 호출된 함수만 실행하도록 설계합니다.
  • 타이머를 설정하고, 그 시간 안에 다음 함수가 호출되지 않으면 해당 함수를 실행합니다.
  • 만약 타이머가 종료되기 전에 함수가 호출된다면 타이머를 삭제하고 다시 타이머를 설정합니다.

이런 방식으로 클로저 함수를 구현합니다.

debounce, debounceFunction을 추가해준 뒤, onChange를 실행하던 곳에서 debounce를 실행합니다.

input에 변경이 일어나면 debounce를 실행하게 되고, 0.3초의 대기시간을 갖고 onChange를 실행시키는 클로저 함수를 호출합니다.

 

이 때 0.3초의 대기시간안에 또 다시 debounce 함수가 실행되면 clearTimeout으로 기존 타이머를 제거한 뒤 다시 setTimeout을 실행합니다.

 

이렇게 구현한 뒤 '토피넛' 입력 후 0.3초 기다린 뒤 '토피넛라떼'를 완성시키면 다음과 같이 검색 요청이 됩니다.

 

만약 debounce를 활용할 컴포넌트가 많아질 것을 대비하여 hooks 형태로 구현할 수도 있습니다.

이렇게 사용하면 다른 컴포넌트에서도 debounce를 활용하기 위해 새로운 함수를 작성할 필요없이 hooks을 호출하여 디바운싱이 가능합니다.

 

 

Reference

 

[React]React Hook에서 Throttle, Debounce 사용

이번 포스팅에서는 React Hook에서 Throttle, Debounce를 사용하는 방법을 소개합니다. 목차 Throttle와 Debounce Lodash의 Throttle 함수 사용 Throttle 함수가 저장된 useCallback Hook 사용 Debounce 함수 Throttle와 Debounce

developer-talk.tistory.com

 

Debounce with React (Custom Hook & lodash)

리액트와 함께하는 디바운스 구현

velog.io

 

KeyboardEvent: isComposing property - Web APIs | MDN

The KeyboardEvent.isComposing read-only property returns a boolean value indicating if the event is fired within a composition session, i.e. after compositionstart and before compositionend.

developer.mozilla.org