useMutation 훅으로 분리하기

3
post-thumbnail

참고로 FSD architecture로 파일 분리가 되어있음.

🎀 훅으로 분리하기 전에 준비

📌 dto 파일 생성해서 타입 모으기

src/shared/api/authentication-api/dto.ts

// login api 파라미터 타입
export interface PostLoginParam {
  email: string;
  password: string;
}

// 성공 응답에 response 타입
export interface LoginSuccessResponse {
  data: {
    accessToken: string;
    refreshToken: string;
  };
}

📌 axios api 파일 생성

src/shared/api/authentication-api/post-login.ts

import { axiosInstance } from '@shared/api/instance';
import { REQUEST_URLS } from '@shared/constants/api';

import { LoginSuccessResponse } from './dto';

const postLogIn = async (email: string, password: string) => {
  const response = await axiosInstance.post<LoginSuccessResponse>(REQUEST_URLS.postSignIn, {
    email,
    password,
  });
  return response.data;
};

export { postLogIn };

login api를 axios를 이용해서 post해주는 코드를 만들었다.

🎀 useMutation hook 생성

src/features/authentication/hooks/use-post-login-mutation.tsx

import { useMutation } from '@tanstack/react-query';

import { LoginSuccessResponse, PostLoginParam, postLogIn } from '@shared/api/authentication-api';

export const usePostLoginMutation = () => {
  return useMutation<LoginSuccessResponse, Error, PostLoginParam>({
    mutationFn: ({ email, password }) => postLogIn(email, password),
  });
};

useMutation에 대한 타입 지정이 중요하다.
처음에 타입 지정해주지 않았더니, 파라미터로 넘겨줄 값들을 일일이 지정해주어야 했다.

declare function useMutation<TData = unknown, TError = DefaultError, TVariables = void, ... > ...;

useMutation에 대한 타입은 위와 같다고 한다.
TData TError TVariables 3개 까지만 타입 지정을 해주었다.

TData : 반환되는 값에 대한 타입
TError : 에러
TVariables : 파라미터 타입

🎀 생성한 hook 사용법

src/features/authentication/ui/login-form.tsx

const { mutate: postLoginMutate } = usePostLoginMutation();

hook으로 생성해둔 usePostLoginMutation에서 postLoginMutate(mutate)를 빼온다.

const handleSubmitLogin: SubmitHandler<PostLoginParam> = async (data) => {
    postLoginMutate({ email: data.email, password: data.password });
};

로그인 버튼을 눌렀을 때 handleSubmitLogin 함수가 실행되게 만들고,
postLoginMutate 에 email과 password 인자 값을 넘겨준다!!

그럼 로그인 잘 된다!!

🎀 성공 / 에러 처리

이렇게만 끝내면 갱.장.히. 아쉽다.
로그인은 성공할 수도 있고 실패할 수도 있다.
해당 부분에 대한 처리는 useMutation에서도 해줄 수 있고, mutate에서도 해줄 수 있다.

그런데 아래 주의사항을 꼭 읽어 보자!

useMutation()에 등록된 콜백 함수들은 컴포넌트가 언마운트되더라도 실행이 되지만, mutate()의 콜백 함수들은 만약 뮤테이션이 끝나기 전에 해당 컴포넌트가 언마운트되면 실행되지 않는 특징을 가지고 있다고 한다.

그래서 다른 페이지로 리다이렉트한다든가, 혹은 결과를 토스트로 띄워주는 것과 같은 로직은 mutate()를 통해 등록해 주어야 한다. 출처

그래서 나는 mutate에서 작업해주었다.

src/features/authentication/ui/login-form.tsx


const handleSubmitLogin: SubmitHandler<PostLoginParam> = async (value) => {
  postLoginMutate(
    { email: value.email, password: value.password },
    {
      onSuccess: () => { // 성공했을 때
        return toast.success('로그인 성공!');
      },
      onError: (error) => {
        // 실패했을 때
        if (error instanceof AxiosError) {
          // axios에서 보낸 에러가 맞다면 true 값 반환
          if (error.response?.status === 400) {
              // error.response?.status 에 number 체크해서 아래 값 반환
              return toast.error('이메일과 비밀번호를 다시 확인해 주세요.');
        }
      }
      return toast.error('로그인 실패.');
	  },
    },
  );
};

🎀 마치며...

  • tanstack query보다 타입스크립트가 더 어렵다
  • 타입 오류 때문에 많이 허덕였다,,, 팀원 H님의 설명을 들으며 반성 하게 되었다. 강의 하나 더 구독해볼까,,,

profile
일단 해. 그리고 잘 되면 잘 된 거, 잘 못되면 그냥 해본 거!

0개의 댓글