Skip to content

Commit

Permalink
Feat: #80 로그인 API 호출 시 useAxios 훅 적용
Browse files Browse the repository at this point in the history
  • Loading branch information
Yoonyesol committed Sep 5, 2024
1 parent 732c374 commit 30faf35
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 17 deletions.
12 changes: 8 additions & 4 deletions src/hooks/useAxios.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useCallback } from 'react';
import errorHandler from '@hooks/errorHandler';
import type { AxiosResponse } from 'axios';
import type { AxiosResponse, AxiosResponseHeaders, RawAxiosResponseHeaders } from 'axios';

type PromiseCallback<T, P extends unknown[]> = (...args: P) => Promise<AxiosResponse<T>>;

Expand All @@ -12,21 +12,24 @@ type PromiseCallback<T, P extends unknown[]> = (...args: P) => Promise<AxiosResp
* @template {unknown[]} P - API 함수에 전달되는 매개변수의 가변인자 타입 배열
* @param {PromiseCallback<T, P>} fetchCallback - API 요청을 수행하는 함수
* @returns {{
* headers: AxiosResponseHeaders | RawAxiosResponseHeaders | undefined; // API 요청의 응답 헤더
* data: T | undefined; // API 요청의 응답 데이터
* error: Error | null; // API 요청 중 발생한 에러
* loading: boolean; // 데이터 로딩 중인지 여부
* fetchData: (...args: P) => Promise<void>; // API 요청을 호출하는 함수
* }}
* @example
* const { data, error, loading, fetchData } = useAxios(fetchCallback) // fetchCallback에서 타입을 반환한다면, 자동 타입 추론이 가능
* const { data, error, loading, fetchData } = useAxios<User[], Parameters<typeof fetchCallback>>(fetchCallback);
* const { headers, data, error, loading, fetchData } = useAxios(fetchCallback) // fetchCallback에서 타입을 반환한다면, 자동 타입 추론이 가능
* const { headers, data, error, loading, fetchData } = useAxios<User[], Parameters<typeof fetchCallback>>(fetchCallback);
*/
export default function useAxios<T, P extends unknown[]>(fetchCallback: PromiseCallback<T, P>) {
const [headers, setHeaders] = useState<AxiosResponseHeaders | RawAxiosResponseHeaders>();
const [data, setData] = useState<T>();
const [error, setError] = useState<Error | null>(null);
const [loading, setLoading] = useState(false);

const clearData = useCallback(() => {
setHeaders(undefined);
setData(undefined);
setError(null);
setLoading(false);
Expand All @@ -37,6 +40,7 @@ export default function useAxios<T, P extends unknown[]>(fetchCallback: PromiseC
try {
setLoading(true);
const response = await fetchCallback(...params);
setHeaders(response.headers);
setData(response.data);
} catch (error: unknown) {
setError(error as Error);
Expand All @@ -48,5 +52,5 @@ export default function useAxios<T, P extends unknown[]>(fetchCallback: PromiseC
[fetchCallback],
);

return { data, error, loading, clearData, fetchData };
return { data, headers, error, loading, clearData, fetchData };
}
37 changes: 24 additions & 13 deletions src/pages/user/SignInPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ import { USER_AUTH_VALIDATION_RULES } from '@constants/formValidationRules';
import FooterLinks from '@components/user/auth-form/FooterLinks';
import AuthFormLayout from '@layouts/AuthFormLayout';
import { useNavigate } from 'react-router-dom';
import axios from 'axios';
import { AxiosError } from 'axios';
import useToast from '@hooks/useToast';
import { login } from '@services/authService';
import { useEffect } from 'react';
import type { UserSignInForm } from '@/types/UserType';
import { useAuthStore } from '@/stores/useAuthStore';
import useAxios from '@/hooks/useAxios';

export default function SignInPage() {
const { onLogin } = useAuthStore();
const { toastError } = useToast();
const navigate = useNavigate();
const { error, fetchData, headers, loading } = useAxios(login);

const {
register,
Expand All @@ -29,23 +32,31 @@ export default function SignInPage() {
},
});

const onSubmit = async (data: UserSignInForm) => {
try {
const response = await login(data);
const accessToken = response.headers.authorization;
if (!accessToken) return toastError('로그인에 실패했습니다.');
const onSubmit = async (formData: UserSignInForm) => {
await fetchData(formData);
};

const token = accessToken.split(' ')[1];
onLogin(token);
useEffect(() => {
if (headers) {
const accessToken = headers.authorization;
if (!accessToken) {
toastError('로그인에 실패했습니다.');
return;
}

onLogin(accessToken.split(' ')[1]);
navigate('/', { replace: true });
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 401) {
return toastError('아이디와 비밀번호를 한번 더 확인해 주세요.');
return;
}

if (error instanceof AxiosError) {
if (error.response?.status === 401) {
toastError('아이디와 비밀번호를 한번 더 확인해 주세요.');
return;
}
return toastError(`로그인 도중 오류가 발생했습니다: ${error}`);
toastError(`로그인 도중 오류가 발생했습니다: ${error.message}`);
}
};
}, [headers, error]);

return (
<>
Expand Down

0 comments on commit 30faf35

Please sign in to comment.