Skip to content

검색 요청 방식 개선 (feat. Debouncing)

iHoHyeon edited this page Mar 23, 2022 · 6 revisions

검색 요청 방식 개선 (feat. Debouncing)

노가리 하우스는 사용자 경험을 위해서 클릭이 없는 자동 검색기능을 제공하고 있습니다.

Untitled

겉보기에는 크게 문제가 없었으나 멘토님이 개선의 여지가 있다고 언질을 주셨고 우리도 개선하자고 이야기가 나왔던 부분이었기 때문에 서비스의 잠재적인 부작용을 줄이는 방식으로 개선하게 되었습니다.

현재 기능의 문제점

  • 현재는 검색바에 input value가 변경되면 무조건 fetch 요청을 보내서 데이터를 검색하여 결과를 받아오게 됩니다. 그 후 받아온 결과를 계속 갱신해주면서 최종적으로 마지막으로 받아온 결과가 사용자에게 보여지게 됩니다.

    Untitled

    딱봐도 부작용이 발생하기 쉽겠죠??

개선점

  • Debouncing 을 이용한 요청 핸들링을 할 수 있었습니다.

    결국에 필요한 정보는 사용자가 마지막에 입력한 정보이기 때문입니다.

    기존의 방식에서는 input 이 변경될 때마다 데이터를 새로 받아와서 갱신하고 마지막에 받아온 데이터가 사용자의 검색바에 입력된 검색에와 동일한 데이터인 경우 렌더링을 하도록 하였습니다.

    요청을Debounce 로 핸들링하게 된다면 위의 방식을 완전히 개선할 수 있습니다.

    기존 방식과 동일하게 input 의 변경을 감지하지만 input 의 변경이 일정시간(0.2 ~ 0.5초 정도)동안 또 감지된다면 검색 요청을 보내지않고 일정시간(0.2 ~ 0.5초 정도)동안 변경이 감지되지 않는다면 사용자가 검색어 입력을 마치고 검색 결과를 기다리고있다고 판단하여 가장 마지막에 입력된 키워드로 검색요청을 보내는 것입니다.

    Debounce 대기시간만큼 응답을 받는 시간이 느려지는 단점이 있겠지만 서버에 무수히 많은 검색 요청을 보내는 것보다 기대할 수 있는 안정성이 더 크다고 생각할 수 있습니다.

적용

  • 기존 코드

    // search-view.tsx
    
    ...
    return (
    	...
    	<SearchInput 
    		ref={inputKeywordRef} 
    		placeholder="🔍 Search ClubHouse" 
    		onChange={searchRequestHandler} 
    	/>
    	...

    SearchInput 이라는 검색창에 onChange 가 발생할 때마다 fetch 요청을 보내라는 searchRequestHandler 를 호출하고 있는 것을 볼 수있습니다.

  • 바뀐 코드

    // search-view.tsx
    
    ...
    const debounceTimeoutIDRef = useRef<NodeJS.Timeout>();
    
    const onChangeHandler = () => {
        if (debounceTimeoutIDRef.current) clearTimeout(debounceTimeoutIDRef.current);
        debounceTimeoutIDRef.current = setTimeout(() => {
          searchRequestHandler();
        }, 200);
      };
    
    ...
    
    return (
    	...
    	<SearchInput 
    		ref={inputKeywordRef} 
    		placeholder="🔍 Search ClubHouse" 
    		onChange={onChangeHandler} 
    	/>
    	...

    검색어의 onChange 마다 검색 요청을 보내지 않고 onChangeHandler 를 호출하도록 했습니다.

    Debouncing 의 핵심은 타겟이 된 이벤트가 발생하고나서 일정시간동안 이벤트가 또 발생하는지를 확인해야합니다.

    따라서 매번 발생될 함수를 저장하는 debounceTimeoutIDRef 를 선언해줍니다.

    검색어가 변경될 때마다 0.2초 후에 검색요청을 보내라는 setTimeout 을 호출함과 동시에 ID를 debounceTimeoutIDRef 에 갱신합니다.

    따라서 이 setTimeout 이 0.2초 이내에 clear되지 않는다면 정해진 시각의 검색어에 기반한 검색요청을 보내게 됩니다.

    만약 0.2초 이내에 새로운 onChange 이벤트가 발생한다면 debounceTimeoutIDRef 에 저장된 setTimeout 의 ID를 이용해서 clearTimeout 을 해주어 해당 콜백이 실행되지 않도록 하고 새로 0.2초 타이머를 갱신하게됩니다.

    이러한 과정이 반복되며 사용자가 0.2초 동안 검색어를 변경하지 않으면 최종적으로 검색 요청을 보내고 응답을 받아서 화면에 검색 결과를 렌더링하게 될 것입니다.

변경 후

  • 이전과 결과는 같으나 보내는 요청이 확연히 줄어듬을 확인할 수 있습니다.

    Untitled

기타

  • 0.2초 정도가 타이핑 속도와 사용자가 기다리는 시간을 고려하는 경우 적절한 시간인지는 잘 모르겠습니다. 사용자 경험에 따라서 Debouncing 시간을 얼마나 책정해야하는지는 더 알아보고 반영해보겠습니다.
  • 현재는 setTImeout 을 지속적으로 clear 해주는 방식으로 구현했는데 더 좋은 방향이 있다면 개선해보겠습니다.