ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] useDebounce custom hook 으로 성능향상 해보기 (feat: Debounce)
    front-end/React 2023. 9. 13. 00:19

    Debounce 란?

    짧은 시간내에 연속 된 함수 및 event 호출시, 호출 되는 모든 함수를 바로 처리하지않고 정해진 딜레이 이후에 한번만 처리 하는 패턴 입니다.

     

    Debounce는 왜 필요할까?

    1. 네트워크 요청의 함수나 전반적인 성능을 향상 시키기 위해서 가장 많이 쓰입니다.

    2. 비용절약 측면에서도 Debounce가 필요한데요, 예를들어  어떠한 서비스앱이 유료 API가 사용되고있는데 , API의 호출 횟수의 따라 비용이 나간다면 debounce 를 사용하여 네트워크 요청의 횟수를 줄일 수 있습니다.

     

    Use case

    1. input의 입력과 동시에 네트워크 요청을 통해 검색 결과를 가져올때

    (유튜브에서 React와 Debounce 관련 설명 영상의 예시가 거의 위의 사용사례로 강의를 합니다.)

    2. 스크롤 / 리사이즈 바탕으로 작업을 할때

    3. 문서 편집 자동저장

     

    간단한 예시를 통해 debounce의 필요성과 재사용성이 높게끔 리액트 커스텀 훅으로 예제를 만들어보겠습니다.

     

    코드 예제

    // Main.jsx
    
    import React, { useEffect, useState } from 'react';
    
    export default function Main() {
    
      const [countries, setCountries] = useState([]);
      const [input, setInput] = useState("");
    
      const getCountries = async () => {
        try {
          const countriesData = await fetch(`https://restcountries.com/v3.1/name/${input}`);
          const json = await countriesData.json();
          setCountries(json);
        } catch (error) {
          console.log(error);
        }
      };
    
      useEffect(() => {
        if(input) getCountries();
      }, [input]);
    
      return (
        <div>
          <input
            type="text"
            value={input}
            onChange={(e) => setInput(e.target.value)}
            placeholder='나라를 검색해보세요.'
          />
          {countries?.length === 0
          	? <strong>나라가 없습니다.</strong>
            : countries?.map((item)=>(
              <div key={item.common}>
              	{item.name.common}
              </div>
          ))}
        </div>
      )
    }

     코드 관련해서 간단하게 설명하자면, restcountries 에서 국가의 정보 관련된 API를 가져옵니다. 그리고 input의 value로 국가를 검색합니다.

    더 쉽게 말해, input에 입력과 동시에 결과를 input의 입력값에 따라 검색 결과를 가져온다고 보면 될것같습니다.

     

    Debounce 를 적용하기전의 모습

    debounce를 적용하기전, 아래의 gif를 통해 검색창에 'korea'를 검색하는것과 'korea'를 검색했을때 네트워크 통신이 몇번이나 이뤄지는지 한번 보겠습니다. 

     

    위 예제를 통해 확인해보면 'korea'의 한글자 마다 네트워크 요청을 보내고있는데요, 이런식으로 input의 값이 바뀔때마다 fetcher 함수를 호출 하고있습니다. 예제의 방법보다는, 유저가 검색창의 입력이 일어나고 fetcher 함수를 호출 하기 전까지 텀(딜레이)가 있다면 효율적인 함수 호출이 가능해집니다.

     

    그래서 이런 부분을 보다 효율적으로 바꾸기 위해 debounce를 적용 하면 성능이 개선 될 수 있습니다.

     

     

    useDebounce Custom Hook 만들어보기

    // useDebounce.js
    
    import { useEffect, useState } from "react";
    
    //delay 같은경우 보통 500ms 을 사용한다고 합니다.
    function useDebounce(value, delay = 2000) {
      const [debounceVal , setDebounceVal] = useState(value);
    
      useEffect(()=>{
        const handler = setTimeout(()=>{
          setDebounceVal(value);
        },delay);
        return () => {
          clearTimeout(handler);
        }
      },[value,delay])
      return debounceVal;
    }
    
    export default useDebounce;

    우선 리액트 네이밍 컨벤션  , hook 같은 경우 앞에 'use..~' 가 붙으니 useDebounce 라는 커스텀 훅 파일을 하나 생성을 해줍니다.

    위의 코드를 간단하게 설명하자면, 두가지의 인자를 custom hook에 받습니다. 첫번째 인자는 value를 받는데 , 이전 Main.jsx 에서

    input state 값을 인자로 받습니다. 그리고 두번째는 setTimeOut의 delay의 값을 넣어주는데 , 기본값을 보통은 500ms로 지정하지만

    저는 확실하게 debounce가 되는지를 위해 2000ms 으로 지정 했습니다.

     

    useDebonce hook에 또 다른 state를 생성 하는데 전달받은 value의 인자값을 debounceVal의 state에 초기값 설정을 해줍니다.

    그리고 마지막으로 useEffect로 전달받은 인자 value의 값이 업데이트 될때마다 setTimeOut의 함수가 호출이 되어, setDebounce를 통해 최신 value(debounceVal)리턴 해줍니다.

     

     

    Debounce 를 적용하고나서의 모습

    useDebounce의 delay 인자의 초기값을 2000ms로 해서 꽤 시간이 걸리네요ㅎㅎ..

    그래도 debounce를 적용하기전에는 한글자 한글자 마다 네트워크 요청이 이뤄졌었는데 , useDebounce 커스텀 훅으로 유저의 이벤트가 끝나고 2000ms이 지난 후 한번만 'korea' 네트워크 요청을 하는것을 볼 수 있습니다.

     

     

    Reference

    https://www.youtube.com/watch?v=gwIkg1acujU&t=97s 

    https://www.youtube.com/watch?v=d8CTMD2aang 

     

     

     

Designed by Tistory.