React 학습 후에 처음으로 프로젝트를 진행해보면서 axios를 처음 사용해보게 되었다.
처음 axios는 아래와 같이 사용했었다.
//board list component
import axios from 'axios';
//....
function BoardPage() {
const [params] = useSearchParams();
const pageNum = params.get('pageNum') == null ? 1 : params.get('pageNum');
const [data, setData] = useState([]);
//...
useEffect(() => {
getBoardList(pageNum);
}, [pageNum]);
const getBoardList = async (pageNum) => {
await boardAxios.get(`http://localhost:9096/board?pageNum=${pageNum}`)
.then(res => {
setData(res.data.content);
}
.catch(err => {
console.error('boardList axios error : ', err);
}
}
//....
}
//imageBoard list component
import axios from 'axios';
//....
function imagePage() {
const [params] = useSearchParams();
const pageNum = params.get('pageNum') == null ? 1 : params.get('pageNum');
const [data, setData] = useState([]);
//...
useEffect(() => {
getImageBoardList(pageNum);
}, [pageNum]);
const getImageBoardList = async (pageNum) => {
await boardAxios.get(`http://localhost:9096/image-board?pageNum=${pageNum}`)
.then(res => {
setData(res.data.content);
}
.catch(err => {
console.error('imageBoardList axios error : ', err);
}
}
//....
}
이렇게 일단 작성해두고 테스트를 진행 해 정상적으로 동작하는 것을 확인하고 나니 좀 불편한게 눈에 들어왔다.
가장 먼저 눈에 들어온것이 axios를 요청하는 url 작성이었다.
이걸 어쩔까 하다가 생각난 방법이 .env에 기본 url과 크게 분류되어있는 기능의 url을 작성해 두고 가져다 사용하는 방법이었다.
//.env
REACT_APP_API_URL=http://localhost:9096
REACT_APP_API_BOARD=/board/
//...
//board list component
import axios from 'axios';
//....
const default_url = process.env.REACT_APP_API_URL;
const board_default_url = process.env.REACT_APP_API_BOARD;
function BoardPage() {
const [params] = useSearchParams();
const pageNum = params.get('pageNum') == null ? 1 : params.get('pageNum');
const [data, setData] = useState([]);
//...
useEffect(() => {
getBoardList(pageNum);
}, [pageNum]);
const getBoardList = async (pageNum) => {
await boardAxios.get(`${default_url}${board_default_url}?pageNum=${pageNum}`)
.then(res => {
setData(res.data.content);
}
.catch(err => {
console.error('boardList axios error : ', err);
}
}
//....
}
이전보다는 url 관리도 쉽겠구나 하긴 했지만 컴포넌트 몇개 더 작성하다보니 계속 env 파일에서 불러와야 한다는 점이 너무 불편했다.
만약 env 파일에 작성한 변수명이 달라지면 그건 그거대로 일이 커질 것이라는 생각도 들었다.
그리고 가장 큰 문제는 JWT 토큰을 모두 쿠키에 담아 저장하다보니 withCredentials 옵션을 설정해야 하고 headers 역시 매번 작성해야 했다.
테스트 코드는 이런 문제를 다 배제하고 단순하게 연결만 테스트 했기 때문에 문제가 없었지만...
그래서 방법을 알아보다 axios를 모듈화 할 수 있다는 것을 알게 되었다.
처음에는 간단하게 기본적인 설정에 대한 인스턴스만 생성했지만 이미지 파일에 대한 처리도 해야 했고 컴포넌트에서 기능별로 크게 분리되어있는 url 역시 작성하지 않도록 하기 위해 좀 세분화해서 모듈화를 하게 되었다.
//customAxios.js
import axios from 'axios';
/*
* axios list
* board
* image_default
* image_multipart
* image_blob
* ...
*/
const default_url = process.env.REACT_APP_API_URL;
const board_default = process.env.REACT_APP_API_BOARD;
const image_default = process.env.REACT_APP_API_IMAGE;
const comment_default = process.env.REACT_APP_API_COMMENT;
const member_default = process.env.REACT_APP_API_MEMBER;
const default_header = {
'Content-Type': 'application/json',
}
export const boardAxios = axios.create({
baseURL: `${default_url}${board_default}`,
headers: default_header,
withCredentials: true,
});
export const imageAxios = axios.create({
baseURL: `${default_url}${image_default}`,
headers: default_header,
withCredentials: true,
});
export const imageDisplayAxios = axios.create({
baseURL: `${default_url}${image_default}`,
headers: default_header,
withCredentials: true,
responseType: 'blob',
});
export const imageInsertAxios = axios.create({
baseURL: `${default_url}${image_default}`,
headers: {
'Content-Type' : 'multipart/form-data',
},
withCredentials: true,
});
export const axiosErrorHandling = (err) => {
const err_code = err.response.status;
if(err_code === 403) {
window.location.href = '/error';
}//...
}
//...
header의 경우 딱히 여러가지를 사용할 만한것 없이 Content-Type 만 사용하는 것으로도 괜찮았기 때문에 해당 설정 역시 변수화해서 기본 적인 header를 갖는 axios는 그대로 가져다 사용하도록 처리했다.
그리고 image의 경우 파일을 응답받는 경우와 파일을 담아 요청하는 경우 Content-Type이 다르기 때문에 이때만 직접 작성했다.
axios 요청 이후 오류 코드 응답이 오는 경우도 모듈화를 하기 위해 axiosErrorHandling 을 만들어두고 특정 오류코드에 대한 핸들링을 할 수 있도록 했다.
//board list component
import { boardAxios, axiosErrorHandling } from '../../../modules/customAxios';
//....
function BoardPage() {
const [params] = useSearchParams();
const pageNum = params.get('pageNum') == null ? 1 : params.get('pageNum');
const [data, setData] = useState([]);
//...
useEffect(() => {
getBoardList(pageNum);
}, [pageNum]);
const getBoardList = async (pageNum) => {
await boardAxios.get(`?pageNum=${pageNum}`)
.then(res => {
setData(res.data.content);
}
.catch(err => {
axiosErrorHandling(err);
}
}
//....
}
모듈화를 하게 되면서 컴포넌트 코드가 엄청 간결해졌고 나중에 url 변경이나 header 등등 설정의 수정에 있어서도 대응하기 굉장히 좋아졌다.
아쉬운점으로는 대부분의 요청 헤더가 비슷한만큼 하나의 대표적인 기본 설정을 두고 그 설정에 set 해서 url만 수정한다거나 할 수 있도록 만든다면 더 좋지 않을까 싶긴 한데 방법을 찾지도, 딱히 생각나는 것도 없어서 일단은 보류..
'Front > React' 카테고리의 다른 글
React에서 state 배열 관리 및 반복문에서의 state (0) | 2024.04.13 |
---|---|
React 페이지 이동 (1) | 2024.04.12 |
React useParams(), useSearchParams() (1) | 2024.04.12 |
React에서 .env 사용 (0) | 2024.04.11 |
useState 사용 정리 (0) | 2024.04.11 |