본문 바로가기
Front-End/React

[React] 디바운스로 추천 검색 기능 구현하기

by SeanK 2023. 11. 7.

안녕하세요 :)

오늘 기능 테스트를 하다 이상한 문제를 발견했습니다.

 

문제

검색창에  관련 검색 추천리스트를 아래에 보여주도록 검색바 기능을 업그레이드했습니다. 근데 "디오"를 검색하면 "디"의 검색 결과가 나타나는 현상이 발생했습니다. 더군다나 키워드에 따라 추천 리스트가 제대로 나타나는 경우가 있고 아닌 경우가 있었습니다.

 

원인

자세히 살펴보니 이 문제는 한글의 문자표현 + 다른 리스폰스 시간에 따른 에러였습니다.

 

검색창에 입력되어 추천리스트 api 요청이 이루어지기 전에 어떤 키워드가 api 요청되는지 콘솔로 확인해 본 결과입니다.

"디오"를 완성하기 위해 "딩"에서 "디오"로 넘어가기 전에 "디"라는 키워드가 api 요청되는 것을 확인할 수 있습니다.

 

왜 이런 문제가 발생하는 것일까요?

 

이는 한글에는 받침이 있기 때문입니다. "딩"에서 "디오"로 넘어가는 순간 아마 아래와 같은 작업이 이루어질 겁니다.

 

1. "딩"을 삭제하고 "디"를 입력한다.

2. "디"뒤에 "오"를 붙인다.

 

그리고 1변 과정에서 텍스트가 변화했으니 api가 트리거 되는 것이죠.

 

다른 키워드라면 이런 문제가 발생했다고 하더라도 제대로 리스트가 반환될 수 있었겠지만,

아래와 같이 "디"를 입력했을 때 추천 리스트는 163개인 반면 "디오"는 9개였기 때문에 리스폰스에 차이가 발생했습니다.

 

그 결과 "디오" 추천 리스트가 먼저 서버로부터 회신되고 "디"의 추천 리스트가 도착하면서 최종적으로 "디"의 결과가 화면에 나타난 것이었습니다.

"딩"의 리스폰스 타임 37.59ms

 

"디"의 리스폰스타임 42.55ms

 

해결방법

아차 싶었던 저는 본능적으로 해결방법을 깨닫게 되었습니다. 옛날에 어려워서 대충 알고 넘겼던 "디바운드"의 개념을 적용하는 것이지요.

혹시 디바운드의 개념을 잘 모르시는 분들은 이전 블로그에 정리를 해놓았으니 찾아서 보시면 좋을 듯합니다.

 

리엑트 코드는 아래와 같습니다.

//Input창 값이 변경될 때 마다 호출
const handleChange = async (event) => {
const query = event.target.value
setInputText(query)
	if (query.length === 0) {
  	clearStates()
  	return
	}
	setCandidateCompanies(query)
}

//디바운스 함수
  const debounce = (callback, delay) => {
    let timerId = null;
    return (...args) => {
      if (timerId) clearTimeout(timerId);
      timerId = setTimeout(() => {
        callback(...args);
      }, delay);
    };
  };

//추천 리스트 api를 호출해 state를 변경하는 함수 
  const setCandidateCompanies = useCallback(
    debounce((query) => getCandidateCompanies(query), 300)
  , [])

 

여기서 주의 깊게 보셔야할 부분은 useCallback입니다.

useCallback을 사용하지 않으면 아마 디바운스가 동작하지 않을 겁니다.

 

만약 useCallback이 싫으시다면 timerId를 useRef를 통해 저장하는 방법도 가능합니다.

 

요지는 리렌더링이 되더라도 timerId가 null이 되지 않고 이전의 setTimeout값을 가지도록 해주는 것입니다.