[useQuery] api 중복 호출 방지 hook 만들기!

이나원·5일 전
0

개발일지

목록 보기
30/33
post-thumbnail

💡 회사에서 근태 관리 서비스를 만들던 도중, 결재 승인 내역 조회 시, 회사 내 센터 리스트 ID 값과 승인 상태, 신청 구분, 현재 페이지 값이 변할 때 마다 api가 재 호출되어 화면을 갱신해야 했다. 있는 그대로 api를 호출하게끔 작성하고 보니 하나의 api가 여러번 중복 호출되는 현상을 발견하였다. 이를 해결하기 위해 커스텀 훅을 만들었는데 그 과정을 알아보자!

중복 호출 방지 Hook

import { useState, useEffect } from 'react';
import { isEqual } from 'lodash';

const useSetTimeout = <T>(value: T, delay: number): T => {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    if (value == null) return;

    const timer = setTimeout(() => {
      if (!isEqual(value, debouncedValue)) {
        setDebouncedValue(value);
      }
    }, delay);

    return () => clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
};
  • 이 훅은 value라는 입력값이 자주 바뀔 때, 지정한 시간(delay)이 지난 후에만 실제 값(debouncedValue)을 업데이트하도록 만들어진 디바운스(debounce)용 커스텀 훅이다.

  • 변경이 감지되면, 지정한 시간(delay)만큼 기다린 후에 value와 현재 debouncedValue를 lodash.isEqual()로 비교해 값이 다를 때만 setDebouncedValue(value)를 호출함으로써 불필요한 상태 변경을 방지할 수 있다.

  • 마지막으로 cleanup 함수로 이전 타이머를 취소함으로써, value가 빠르게 연달아 바뀌면 타이머가 계속 리셋되고, 최종 입력만 적용된다.

사용 예시

const rawParams = useMemo(() => {
  if (!currentTeamId || !category) return undefined;
  return {
    teamId: currentTeamId,
    category,
    status,
    page: activePage,
  };
}, [currentTeamId, category, status, activePage]);

const debouncedParams = useSetTimeout(rawParams, 300);

위처럼 쓰면 queryKey가 사용자의 입력 등으로 자주 바뀌더라도, 마지막 변경 후 일정 시간이 지나야 반영되어 API 호출이 줄어든다!

퍼포먼스 결과

  • (커스텀 훅 적용 전 (호출 3번))

  • (커스텀 훅 적용 후 (호출 1번))

  • 항목변경 전 (3회 호출)변경 후 (1회 호출)
    총 렌더링 시간3,511ms2,561ms
    System 처리 시간1,021ms689ms
    Scripting 시간537ms624ms
    Painting 시간109ms60ms

약 27%의 총 렌더링 시간 감소를 달성하여 페이지 로딩 시의 체감 속도를 변화시켰다! 이번 과정을 통해 불필요한 네트워크 낭비를 줄이고, 최적화를 이루어내서 뿌듯하다!

profile
프론트엔드 개발자로 재직 하면서 겪은 개발 과정을 기록하는 곳입니다 🙌

0개의 댓글