카테고리 없음

React debounce(리액트 디바운스)

ecoEarth 2023. 8. 23. 20:48
출처: https://www.youtube.com/watch?v=d8CTMD2aang
위 유튜브 영상을 보고 정리한 글입니다.

debounce

디바운스는 이벤트중에서도 특히 연속된 이벤트를 처리할때 유용하게 사용됩니다.

실생활에 가까운 예시를 들자면, 네이버의 검색창의 자동완성 기능이 있습니다.

사용자의 키보드이벤트가 끝난 시점을 

 

자동완성기능에 굳이 debounce를 사용해야 합니까?

'자동완성'이라는 키워드로 자동완성을 나타내기 위해서는 onChange를 통해 ㅈ, 자, 자ㄷ, 자도, 자동, 자동ㅇ....등등 모든 연속적인 키보드 이벤트마다 request를 보내기보다는 자,자동,자동완,자동완성 등 의미있는 철자를 통해 request를 보내는 것이 서버비용에도, 클라이언트의 성능상 문제에도 적합할 것입니다.

그러면 자음과 모음의 조합이 성립할때만 검색하게 해주면 어떨까요? 예를들어 '자'라는 키워드가 검색창에 올려져있다 가정해보자구요.

분명 자음만 있는것도 아니고, 모음만 있는것도 아니고 자음과 모음의 조합이 성립합니다. 하지만 사용자가 '잠만보'를 검색할 것인지 '자동차'를 검색할 것인지 '자'가 완성된 시점에는 알지 못하기때문에 자음과 모음의 조합이 되었을때만 검색하는건 좀 비효율적입니다.

또는 'naver'라는 키워드도 n,a,v,e,r 5번의 API요청을 하는것보다는, 키보드입력이 끝난뒤 일정시간이 지난 후 마지막 호출에서만 검색키워드에 대한 API를 해주는게 좋겠죠. 그게 debounce입니다. debounce를 통해 전반적인 성능향상과 비용절약을 얻을 수 있습니다.

 

어디에서 쓰이나요?

1. 검색어 입력과 동시에 네트워크 요청을 통한 검색결과를 가져와야 할때 쓰입니다. 자동완성기능에 적합하겠죠

2. 스크롤/리사이즈 이벤트 바탕으로 작헙할때도 쓰입니다.

3. 문서 편집 자동저장에도 유용합니다. 

 

 

어떻게 쓰나요?

 

// useDebounce 커스텀 훅 생성

import { useEffect, useState } from "react";

function useDebounce(value, delay = 500) {
  const [debounceVal, setDebounceVal] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebounceVal(value);
    }, delay);
    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debounceVal;
}

export default useDebounce;

 

// 만들어둔 커스텀 훅 사용

import { useEffect, useState } from "react";
import "./App.css";

import useDebounce from "./useDebounce";

function CountryList({ countries }) {
  if (!countries) return;
  return countries.map((country) => {
    return (
      <div key={`${country.area}`}>
        <span>{country.name.official}</span>{" "}
        <img
          style={{ width: "120px", height: "80px" }}
          src={country.flags.png}
          alt={country.name.common}
        />
      </div>
    );
  });
}

export default function App() {
  const [search, setSearch] = useState("");
  const [countries, setCountries] = useState(null);

  const debounceValue = useDebounce(search);

  useEffect(() => {
    const getCountries = async () => {
      return await fetch(
        `https://restcountries.com/v3.1/name/${debounceValue}`
      )
        .then((res) => {
          if (!res.ok) {
            return new Promise.reject("no country found");
          }
          return res.json();
        })
        .then((list) => {
          setCountries(list);
        })
        .catch((err) => console.error(err));
    };
    if (debounceValue) getCountries();
  }, [debounceValue]);

  return (
    <div className="App">
      <input
        type="search"
        placeholder="Search Countries"
        onChange={(e) => setSearch(e.target.value)}
      />
      <hr />
      {search ? <CountryList countries={countries} /> : ""}
    </div>
  );
}