본문 바로가기
📄Today I Learned

연락처가 추가됐는데, 왜 화면엔 갱신이 안될까?

by 영진학생 2025. 4. 24.

문제 상황

  • AddContactForm에서 연락처 추가 후 Supabase 저장까지는 잘 됐는데, 일반 연락처 리스트(regularContacts)에 바로 반영되지 않음
  • 화면은 여전히 과거 데이터를 보여줌

원인을 한번 찾아볼까?

처음엔 React Query의 쿼리 키(queryKey)가 달라서 발생한 문제라고 생각했다. 그래서 관련 코드를 다시 확인해봤다.

점검했던 코드

  • mutation 훅:
export const useMutateInfiniteContact = (userId?: string) => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: ({ contactId, isPinned }: { contactId: string; isPinned: boolean }) => 
      mutateUpdateContactPin(contactId, isPinned),
    onSuccess: () => {
      if (!userId) return

      queryClient.invalidateQueries({
        queryKey: [QUERY_KEY.CONTACTS, 'pinned', userId],
      })

      queryClient.invalidateQueries({
        queryKey: [QUERY_KEY.CONTACTS_INFINITE, 'regular', userId],
      })
    }
  });
}
  • 쿼리 키 설정:
export const QUERY_KEY = Object.freeze({
  HOLIDAYS: 'holidays',
  CONTACTS: 'contacts',
  PLANS: 'plans',
  CONTACT_WITH_PLANS: 'contactWithPlans',
  SELECT_PLAN: 'selectPlan',
  CONTACTS_INFINITE: 'contactsInfinite'
});
  • 연락처 조회 훅:
export const usePinnedContacts = (userId: string) =>
  useQuery({
    queryKey: [QUERY_KEY.CONTACTS, 'pinned', userId],
    queryFn: () => fetchPinnedContacts(userId),
  });

export const useRegularContactsInfinite = (userId: string) =>
  useInfiniteQuery({
    queryKey: [QUERY_KEY.CONTACTS_INFINITE, 'regular', userId],
    queryFn: ({ pageParam = 0 }) => fetchRegularContactsInfinite(userId, pageParam),
    getNextPageParam: lastPage => lastPage.nextPage,
    initialPageParam: 0,
  });

하지만 확인 결과, 쿼리 키는 정확히 일치했고 문제가 아니었다. 이후 React Query의 공식 문서를 다시 확인해 invalidateQueries 대신 resetQueries나 refetch: 'all' 같은 방법도 시도했지만 해결되지 않았다.

진짜 원인은?

문제의 원인은 useContactForm의 onSubmit 함수에 mutation 호출 로직이 빠져 있었기 때문이었다. 즉, 데이터가 Supabase에 저장된 이후 React Query의 무효화(invalidate)가 실행되지 않아 화면이 갱신되지 않았다.

어떻게 해결했나?

  • React Query의 useMutation으로 데이터를 저장하는 로직을 구현
  • 저장 완료 후 성공 콜백(onSuccess)에서 관련된 쿼리를 무효화

수정한 코드

export const useContactForm = () => {
  const queryClient = useQueryClient();
  const { user } = useAuthStore();
  const userId = user?.id!;

  const insertContact = useMutation({
    mutationFn: (contact: Omit<ContactDetailType, 'contacts_id'>) => mutateInsertContacts(contact),
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: [QUERY_KEY.CONTACTS, 'pinned', userId],
      });
      queryClient.invalidateQueries({
        queryKey: [QUERY_KEY.CONTACTS_INFINITE, 'regular', userId],
      });
      toast.success('연락처가 리스트에 반영되었습니다.');
    },
    onError: () => {
      toast.error('연락처 저장에 실패했습니다.');
    },
  });

  const onSubmit = (data: ContactFormValues) => {
    const contactData = { /* 필드 매핑 */ };
    insertContact.mutate(contactData);
  };

  return { form, onSubmit, isSubmitting: insertContact.isLoading };
};

추가적으로 알게 된 점

연락처 상세 페이지에서 삭제 버튼도 같은 문제를 가질 가능성이 있어, 이 부분을 담당한 팀원에게 상황을 전달하고 수정 요청을 할 필요가 있다는 점도 발견했다.

최종 결과

  • 연락처 추가 후 화면이 즉시 업데이트된다.
  • React Query가 자동으로 데이터를 다시 불러와 리스트가 최신으로 유지됨
  • 팀원에게 문제를 공유하여 추가적인 코드 개선까지 진행함

이렇게 문제를 해결하며 코드 품질과 협업의 중요성을 다시 한번 깨닫게 되었다.