React로 작업하다보면 Network를 통신을 위한 공통 모듈을 작성할 필요가 있습니다.
공통 모듈을 통해 아래 사항을 공통적으로 관리할 수 있습니다.
* 요청 URL
* Timeout
* 인증 관련 로직
* 사용 방법
직접 만드는 것이 유지보수와 커스텀 차원에서 장점이 있다고 생각해 외부 라이브러리르 쓰는 것보다는 직접 custom hook을 직접 만들어 쓰고 있습니다.
실제 사용 시에는 refresh, access token의 만료기간을 체크하는 로직까지 들어 있습니다.
하지만 이는 어떻게 Backend가 구성되어 있느냐에 따라 달라지는 부분이라고 생각 들어 Recoil에 access token 이 있다면 해당 토큰을 사용해서 요청하는 정도로만 해서 참고하실 수 있게 코드 공유드립니다.
network.hook.ts
import axios, {AxiosError, AxiosRequestConfig, AxiosResponse} from 'axios';
import {useEffect, useState} from 'react';
import {useRecoilValue} from 'recoil';
import {authState} from '../recoils/AuthRecoil';
import {AuthTokens} from '../type/auth';
import {SERVER_HOST} from '../constants/url.constants';
type AxiosOption = {
disableInitialRequest: boolean;
};
export const useAxios = <R>(requestConfig: AxiosRequestConfig) => {
const [response, setResponse] = useState<R>();
const {
response: promiseResponse,
error,
loading,
} = useAxiosPromise<R>(requestConfig);
void promiseResponse?.then(r => {
setResponse(r.data);
});
return {
response,
error,
loading,
};
};
export const useAxiosPromise = <R>(
paramAxiosConfig: AxiosRequestConfig,
options: AxiosOption = {
disableInitialRequest: false,
},
) => {
const [response, setResponse] = useState<Promise<AxiosResponse<R>>>();
const [error, setError] = useState<AxiosError>();
const [loading, setLoading] = useState(true);
const tokens = useRecoilValue<AuthTokens>(authState);
const fetchData = (axiosConfig: AxiosRequestConfig) => {
const url = axiosConfig.url || '';
axiosConfig.url = url.startsWith('http') ? url : SERVER_HOST + url;
try {
setLoading(true);
const result = axios.request({
timeout: 5000,
...axiosConfig,
headers: {
Authorization: tokens.accessToken && `Bearer ${tokens.accessToken}`,
...axiosConfig.headers,
},
});
setResponse(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
useEffect(() => {
if (options.disableInitialRequest) {
return;
}
void fetchData(paramAxiosConfig);
}, []);
return {
response,
error,
loading,
refetch: (newRequestConfig: Partial<AxiosRequestConfig>) => {
void fetchData({
...paramAxiosConfig,
...newRequestConfig,
});
},
};
};
사용처
// hook을 통한 관련 객체 획득
const {response, error, loading, refetch} = useAxiosPromise<LoginResponse>(
{
method: 'post',
url: '/auth/social/kakao',
headers: {
'kakao-access-token': accessToken,
},
},
{disableInitialRequest: true}, // 화면 최초 로딩 시 요청 여부 설정. default는 false이며 최초 요청 불필요할 때만 true 설정.
);
// 특정 조건에 refetch로 백엔드 요청
useEffect(() => {
if (!dependency) {
return;
}
refetch({
headers: {
'custom header': dependency,
},
});
}, [dependency]);
// refetch로 인해 response 바뀌었을 때 관련 후속 처리 진행
useEffect(() => {
if (!response) {
return;
}
void response
.then(r => r.data)
.then(data => {
// ... action ...
});
}, [response]);
'제안&정리' 카테고리의 다른 글
[React, React Native] Update 구독/발행 (0) | 2022.09.11 |
---|---|
Latency 관리 (0) | 2022.08.21 |
안정적인 서버 운영을 위한 Health Check - 4xx vs 5xx (0) | 2022.07.10 |
Application Scaling 전략 (0) | 2022.07.03 |
React Native - NumberInput (0) | 2022.06.25 |