본문 바로가기

공부/프로젝트

[개인 프로젝트] MBTI 테스트 - useQuery, useMutation 커스텀 훅 리팩토링

반응형

리팩토링 이유 📖

Tanstack Query를 사용하면서 여러 컴포넌트에서 중복되는 로직이 발생해 유지보수가 어렵다는 생각이 들었습니다. 그래서 `useQuery`와`useMutation`을 커스텀 훅으로 리팩터링 하고 `queryKey`를 상수화 해 코드의 가독성과 재사용성을 높인 방법에 대해서 공유해보려고 합니다.

 

기존 코드 📖

useQuery, useMutation

기존에는 `useQuery`와 `useMutation`을 각 API 호출마다 직접 사용했는데, 여러 컴포넌트에서 중복되는 로직이 많아지고 가독성이 떨어 지는 문제가 있었습니다.

const { data: results, isLoading } = useQuery({
  queryKey: ["results"]
  queryFn: getTestResults,
});

const { mutate } = useMutation({
  mutationFn: updateTestResultVisibility,
  onSuccess: () => {
    queryClient.invalidateQueries(["results"]);
  },
})

 

 그리고 `queryKey`를 직접 작성하다보니 지금은 상관없지만 팀 프로젝트와 같이 여러 명이 같이 수정하는 상황에서는 알파벳 하나 잘못 쓰는 걸로 휴먼 에러가 발생할 수 도 있는 상황이 생길 수 있기 때문에 리팩토링을 결정했습니다.

queryKey: ["results"]

 

리팩토링 코드 📖

queryKey 상수화

먼저 `queryKey`상수로 관리해 재사용할 수 있게 했습니다.

export const queryKeys = {
  userController: {
    userInfo: () => ["userInfo"],
  },
  resultController: {
    results: () => ["results"],
  },
};

 

useQuery 분리

여러 컴포넌트에서 사용하는 useQuery를 `useQuerys.js`파일을 따로 만들어서 분리시켰습니다.

// 사용자 프로필 가져오기
export const useGetUserProfileQuery = () => {
  return useQuery({
    queryKey: queryKeys.userController.userInfo(),
    queryFn: getUserProfile,
  });
};

// MBTI 결과 가져오기
export const useGetTestResultsQuery = () => {
  return useQuery({
    queryKey: queryKeys.resultController.results(),
    queryFn: getTestResults,
  });
};

 

useMutation 분리

useMutation도 `useMutations.js`파일을 따로 만들어서 분리를 시켰습니다.

// 공개, 비공개 전환 업데이트
export const useUpdateVisibilityMutation = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: updateTestResultVisibility,
    onSuccess: () => {
      queryClient.invalidateQueries(queryKeys.resultController.results());
    },
  });
};

// MBTI 결과 삭제
export const useDeleteTestResultMutation = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: deleteTestResult,
    onSuccess: () => {
      queryClient.invalidateQueries(queryKeys.resultController.results());
    },
  });
};

// 닉네임 업데이트
export const useUpdateNicknameMutation = () => {
  const queryClient = useQueryClient();
  const [data, setData] = useState(null);

  return useMutation({
    mutationFn: updateProfile,
    onSuccess: (response) => {
      setData(response);
      queryClient.invalidateQueries(queryKeys.userController.userInfo());
    },
  });
};

 

컴포넌트

해당 컴포넌트에서 호출해 간편하게 사용할 수 있습니다.

const { data: results, isPending, isError } = useGetTestResultsQuery();
const { mutate: updateMutate } = useUpdateVisibilityMutaion();
const { mutate: deleteMutate } = useDeleteTestResultMutaion();

 

회고 🧐

가독성, 재사용성

API 호출 로직을 분리해 코드가 깔끔해졌고, 동일한 API 호출 로직을 여러 컴포넌트에서 재사용할 수 있어 중복을 줄였습니다. 이번 리팩토링을 통해 코드의 품질과 유지보수성을 크게 향상할 수 있었고 쿼리키를 상수화 시킨 방법은 나중에 협업을 진행할 때 아주 긍정적인 영향이 미칠 것 같습니다. 

아직 많이 부족합니다! 조언은 언제나 환영입니다~!

반응형