본문 바로가기
카테고리 없음

useQuery `placeholderData`

by LucetTin5 2025. 9. 21.

React Query placeholderData 활용 경험 정리

카드번호 앞 6자리(BIN)로 체크/신용 여부, 카드사, 카드 이름 등을 조회하는 API를 연동하는 과정에서 작은 이슈를 겪었습니다. orval을 사용해 React Query 훅을 자동 생성하고 있었는데, 입력이 6자리에서 7자리, 8자리로 늘어날 때마다 새로운 queryKey가 만들어지고, 그 과정에서 데이터가 잠시 undefined가 되는 문제가 있었습니다.

문제 상황

  • 카드번호 입력이 123456 → 1234567 → 12345678 로 늘어나면서 매번 새로운 queryKey로 fetching 발생
  • 조회된 결과(cardInfo)는 체크카드일 경우, 할부 기간 select를 readonly 처리하는 로직과 연결되어 있었음
  • 문제는 fetching 상태에서 데이터가 undefined로 바뀌면서 select가 깜빡거리듯 회색 → 복원되는 현상이 나타남

즉, 이전 값을 그대로 유지해주고 싶은데 기본 동작만으로는 이를 해결하기 어려웠습니다.

첫 번째 시도

React Query에서 제공하는 placeholderData를 이용하면 이전 쿼리 결과를 임시 데이터로 유지할 수 있습니다. 처음에는 단순히 prev => prev 형태로 작성했습니다.

const { data: cardInfo } = useGetCardInfoByBinCode(
  cardNumber?.slice(0, 8) || '',
  {
    query: {
      enabled: !!cardNumber && cardNumber.length >= 6,
      select: (data: ApiResponseCardInfoResponse) => data.data?.[0],
      placeholderData: (prev) => {
        if (!!cardNumber && cardNumber.length >= 6) return prev;
        return undefined;
      },
    },
  },
);
 
 

6자리 → 7자리 → 8자리로 입력이 늘어날 때는 잘 작동했지만, 문제는 6자리 → 5자리 → 다시 6자리 상황이었습니다. 이 경우 이전 6자리 결과가 그대로 남아 버려 잘못된 데이터를 보여주게 되었습니다.

최종 정리

이를 보완하기 위해, prev와 현재 queryKey를 비교하는 방식으로 정리했습니다.
즉, 같은 BIN(앞 6자리)이면 이전 값을 유지하고, 그렇지 않으면 undefined로 처리합니다.

 
const { data: cardInfo } = useGetCardInfoByBinCode(
  cardNumber?.slice(0, 8) || '',
  {
    query: {
      enabled: !!cardNumber && cardNumber.length >= 6,
      select: (data: ApiResponseCardInfoResponse) => data.data?.[0],
      placeholderData: (prev, query) => {
        const prevPath = query?.queryKey?.[0]; // '/card/bin/000000'
        if (!prevPath || typeof prevPath !== 'string') return undefined;

        const prevCardNumber = prevPath.split('/').pop() || '';
        const prevBinCode = prevCardNumber.slice(0, 6);
        const currentBinCode = cardNumber?.slice(0, 6);

        if (currentBinCode === prevBinCode) return prev;
        return undefined;
      },
    },
  },
);

이렇게 하면,

  • 같은 BIN 범위(6자리 기준)에서는 이전 값을 유지 → 불필요한 깜빡임 방지
  • 다른 BIN으로 넘어갈 때는 정상적으로 undefined 처리 → 잘못된 데이터 노출 방지

정리

React Query의 placeholderData는 단순히 로딩 중 UI를 부드럽게 해주는 것 이상의 역할을 할 수 있습니다. 특히 입력 길이에 따라 queryKey가 세분화되는 API를 다룰 때, 적절한 조건을 걸어주면 사용자 경험을 훨씬 안정적으로 만들 수 있습니다.