Skip to content

Commit

Permalink
Feat: #63 useAxios 트리거 형태로 변경 & API 함수 구조 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
Seok93 committed Aug 18, 2024
1 parent d3554f0 commit 76bbac6
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 31 deletions.
67 changes: 39 additions & 28 deletions src/hooks/useAxios.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,55 @@
import axios from 'axios';
import { useEffect, useState } from 'react';

import { useState, useCallback } from 'react';
import type { AxiosResponse } from 'axios';

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

export default function useAxios<T, P extends unknown[]>(fetchCallback: PromiseCallback<T, P>, ...params: P) {
/**
* Axios API 함수를 처리하는 커스텀 훅
*
* @export
* @template T - AxiosResponse의 응답 데이터 타입
* @template {unknown[]} P - API 함수에 전달되는 매개변수의 가변인자 타입 배열
* @param {PromiseCallback<T, P>} fetchCallback - API 요청을 수행하는 함수
* @returns {{
* 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);
*/
export default function useAxios<T, P extends unknown[]>(fetchCallback: PromiseCallback<T, P>) {
const [data, setData] = useState<T>();
const [error, setError] = useState<Error | null>(null);
const [loading, setLoading] = useState(false);

// ToDo: 성공/실패 토스트 메세지 출력하기
useEffect(() => {
const fetchController = new AbortController();
const { signal } = fetchController;

const fetch = async () => {
const fetchData = useCallback(
async (...params: P) => {
try {
setLoading(true);
const response = await fetchCallback(signal, ...params);
const response = await fetchCallback(...params);
setData(response.data);
} catch (error: unknown) {
if (axios.isAxiosError(error)) {
if (error.request) {
// ToDo: 네트워크 요청을 보냈지만 응답이 없는 경우 에러 처리
} else if (error.response) {
// ToDo: 요청후 응답을 받았지만 200 이외의 응답 코드인 경우 예외 처리
} else {
// ToDo: 그 외 예외 처리
}
setError(error as Error);

if (!axios.isAxiosError(error)) return;

if (error.request) {
// ToDo: 네트워크 요청을 보냈지만 응답이 없는 경우 에러 처리
} else if (error.response) {
// ToDo: 요청후 응답을 받았지만 200 이외의 응답 코드인 경우 예외 처리
} else {
// ToDo: request 설정 오류
}
} finally {
if (!signal.aborted) setLoading(false);
setLoading(false);
}
};
fetch();

return () => {
fetchController.abort();
};
}, [fetchCallback, params]);
},
[fetchCallback],
);

return { data, loading };
return { data, error, loading, fetchData };
}
15 changes: 12 additions & 3 deletions src/services/projectService.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { authAxios } from '@services/axiosProvider';

import type { AxiosRequestConfig } from 'axios';
import type { User } from '@/types/UserType';
import type { Project } from '@/types/ProjectType';

/**
* 프로젝트에 속한 유저 목록을 검색하는 API
*
* @export
* @async
* @param {Project['projectId']} projectId - 프로젝트 아이디
* @param {User['nickname']} nickname - 유저 닉네임
* @param {AxiosRequestConfig} [axiosConfig={}] - axios 요청 옵션 설정 객체
* @returns {Promise<AxiosResponse<User[]>>}
*/
export async function findUserByProject(
signal: AbortSignal | null,
projectId: Project['projectId'],
nickname: User['nickname'],
axiosConfig: AxiosRequestConfig = {},
) {
const axiosConfig = signal ? { signal } : {};
return authAxios.get<User[]>(`project/${projectId}/user/search?nickname=${nickname}`, axiosConfig);
}

0 comments on commit 76bbac6

Please sign in to comment.