useDebounce Custom Hook

hyeryeon·2024년 9월 30일

React

목록 보기
17/19

디바운스(debounce)

디바운스는 입력 값이 빠르게 연속적으로 변할 때, 마지막 입력만을 처리하기 위해 사d용한다.
예를 들어, 사용자가 검색창에 입력할 때마다 검색 요청을 보내는 대신, 입력이 멈추고 일정 시간이 지나면 그때 한 번만 요청을 보내는 것이 효율적이다.

useDebounce 훅의 역할

이 훅은 사용자가 입력하는 값을 받아, 일정 시간(delay)이 지나기 전까지는 값을 변경하지 않다가, 시간이 지나면 그때서야 값을 업데이트한다.

import { useEffect, useState } from "react"

export const useDebounce = (value, delay) => {
  const [devouncedValue, setDevouncedValue] = useState(value)

  useEffect(() => {
    const handler = setTimeout(() => {
      setDevouncedValue(value)
    }, delay)

    return () => {
      clearTimeout(handler)
    }
    //useEffect 안에서 return되는 함수는 컴포넌트가 리렌더링될 때마다 
    //기존의 타이머를 취소해주는 역할을 합니다. 이렇게 하면 이전 타이머가 계속 
    //남아 있지 않고, 최신 value에 대해서만 타이머가 동작하게 됩니다.
  }, [value, delay])
//딜레이가 끝나기전에 종속성배열에따라 useEffect가 다시되면 딜레이시간이 
  //다시 초기화되서 시작
  
  return devouncedValue
}

1. 입력값 처리 (Search Input)

사용자가 검색창에 입력을 하면, 입력값은 onChange 이벤트 핸들러를 통해 searchTerm 상태로 업데이트된다.
이 부분에서 입력한 검색어가 searchTerm에 바로 반영


<form className="relative flex justify-center items-center w-[20.5rem] h-6 rounded-lg m-auto">
  <input
    type="text"
    value={searchTerm}
    onChange={(e) => setSearchTerm(e.target.value)} // searchTerm 업데이트
    className="text-xs w-[20.5rem] bg-[hsl(214,13%,47%)] h-6 px-2 py-1 rounded-lg text-gray-300 text-center"
  />
  <button
    type="submit"
    className="text-xs bg-slate-900 text-slate-300 w-[2.5rem] h-6 px-2 py-1 rounded-r-lg text-center absolute right-0 hover:bg-slate-700"
  >
    검색
  </button>
</form>

onChange 핸들러가 호출될 때마다 setSearchTerm(e.target.value)가 실행되어 searchTerm 상태가 변경된다.

2. Debounce 적용

searchTerm이 변경될 때마다, useDebounce 훅이 실행되어, 입력이 멈추고 500ms 후에만 debouncedSearchTerm이 갱신된다.
사용자가 입력을 계속하는 동안 API 요청이 중복 발생하는 것을 방지하기 위한 것

debouncedSearchTerm은 searchTerm과는 달리, 일정 시간이 지난 후에만 최신 값을 유지합니다.

const debouncedSearchTerm = useDebounce(searchTerm, 500);

3. useEffect로 검색 실행

debouncedSearchTerm이 변경될 때마다, useEffect가 호출된다
사용자가 500ms 동안 입력을 중지하면 그제서야 debouncedSearchTerm 값이 갱신되고, 이때 API 요청을 트리거하는 함수인 handleSearchInput이 호출


useEffect(() => {
  handleSearchInput(debouncedSearchTerm);  // debouncedSearchTerm을 사용하여 API 호출
}, [debouncedSearchTerm]);

4. API 요청 함수 (handleSearchInput)

handleSearchInput은 debouncedSearchTerm을 받아서 그 값이 유효한 경우 포켓몬 API에 요청을 보낸다.
요청 성공 시 포켓몬 데이터를 받아오고, 실패 시에는 빈 배열로 설정하여 "포켓몬이 없습니다."라는 메시지를 표시
만약 debouncedSearchTerm이 빈 문자열이면, 처음 포켓몬 목록을 다시 가져오게 됩니다.

const handleSearchInput = async (searchTerm) => {
  if (searchTerm.length > 0) {
    try {
      const response = await axios.get(`https://pokeapi.co/api/v2/pokemon/${searchTerm}`);
      const pokemonData = {
        url: `https://pokeapi.co/api/v2/pokemon/${response.data.id}`,
        name: searchTerm,
      };
      setPokemons([pokemonData]);  // 검색된 포켓몬만 배열에 저장
    } catch (error) {
      setPokemons([]);  // 에러 발생 시 포켓몬 데이터 초기화
      console.error(error);
    }
  } else {
    fetchPokeData(true);  // 검색어가 없으면 기본 포켓몬 리스트 불러오기
  }
};

요약

  1. 사용자가 검색창에 값을 입력하면, 그 값은 searchTerm에 즉시 반영된다.
  2. useDebounce 훅이 적용되어 searchTerm이 바뀌어도 일정 시간 동안 대기한 후에만 debouncedSearchTerm이 변경됨
  3. debouncedSearchTerm이 바뀌면, useEffect가 실행되어 handleSearchInput을 통해 포켓몬 API에 요청 시작
  4. API 요청 결과에 따라 포켓몬 데이터를 화면에 표시하거나, 검색 결과가 없을 경우 "포켓몬이 없습니다." 메시지를 표시한다.

0개의 댓글