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

+ Recent posts