React에서 Axios 사용하기

김민국·2021년 7월 15일
10

React

목록 보기
1/1
post-thumbnail

axios를 사용해서 GET, PUT, POST, DELETE 등의 메서드로 API 요청이 가능합니다. 각각의 기능은 다음과 같습니다.

  • GET: 데이터 조회
  • POST: 데이터 등록
  • PUT: 데이터 수정
  • DELETE: 데이터 제거

사용법

1. axios(config)

config 설정을 axios()에 전달하여 요청할 수 있습니다

import axios from 'axios';

// url 속성만 필수이고, 나머지 속성은 옵션!
// method가 지정되지 않으면 GET으로 기본 설정됩니다.

// GET 요청 전송
axios({
	url: '/user/12'
});

// DELETE 요청 전송
axios({
	url: '/user/12'
});

// POST 요청 전송
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});

// PUT 요청 전송
axios({
  url: '/user/12345',
  method: 'put',
  data: {
    firstName: 'Fred',
    lastName: 'Flooooooo'
  }
})

2. HTTP 메서드 별칭

import axios from 'axios';

axios.get('/user/12')            // GET
axios.delete('/user/12')         // DELETE
axios.post('/user/12345',{       // POST
    firstName: 'Fred',
    lastName: 'Flintstone'
  })   
axios.put('/user/12345',{        // PUT
    firstName: 'Fred',
    lastName: 'Floooooo'
  })    

useState로 요청 관리하기

요청에 대한 상태를 관리하기 위해서는 3가지 상태를 관리해주어야 합니다.

  1. 요청의 결과 (data)
  2. 로딩 상태 (loading)
  3. 에러 (error)
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function Users() {
  const [users, setUsers] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchUsers = async () => {
    try {
      // 요청이 시작 할 때에는 error 와 users 를 초기화하고
      setError(null);
      setUsers(null);
      // loading 상태를 true 로 바꿉니다.
      setLoading(true);
      const response = await axios.get(
        'https://jsonplaceholder.typicode.com/users'
      );
      setUsers(response.data); // 데이터는 response.data 안에 들어있습니다.
    } catch (e) {
      setError(e);
    }
    setLoading(false);
  };

  useEffect(() => {
    fetchUsers();
  }, []);

  if (loading) return <div>로딩중..</div>; 
  if (error) return <div>에러가 발생했습니다</div>;

	// 아직 users가 받아와 지지 않았을 때는 아무것도 표시되지 않도록 해줍니다.
  if (!users) return null;

	// 드디어 users가 성공적으로 받아와 진 상태입니다.
  return (
		<>
	    <ul>
	      {users.map(user => (
	        <li key={user.id}>
	          {user.username} ({user.name})
	        </li>
	      ))}
	    </ul>
			// button을 클릭하면 API를 다시 불러와줍니다.
			<button onClick={ fetchUsers }>다시 불러오기<button>
		</>
  );
}

export default Users;

직접 해보기


https://codesandbox.io/s/api-integrate-yfwg7?fontsize=14

useReducer로 요청 관리하기

useReducer로 관리할 때 생기는 장점은 다음과 같습니다.

  1. 로직의 재사용이 가능하다.
  2. 컴포넌트 내부의 코드가 짧아진다. (but, reducer 함수의 추가로 전체적인 코드의 길이는 늘어납니다.)

이제 같은 코드를 useReducer로 변경 해보겠습니다.

reducer 작성하기

function reducer(state, action) {
  switch (action.type) {
		// 발생할 수 있는 상황 LOADING, SUCCESS, ERROR에 대한 case를 만들어 줍니다.
		// 로딩중 상태 업데이트
    case 'LOADING':
      return {
        loading: true,
        data: null,
        error: null
      };
		// 불러오는데에 성공했을 때는 action.data를 저장해줍니다.
    case 'SUCCESS':
      return {
        loading: false,
        data: action.data,
        error: null
      };
		// 에러가 발생하면 action.error를 전달해주겠습니다.
    case 'ERROR':
      return {
        loading: false,
        data: null,
        error: action.error
      };
    default:
      throw new Error(`Unhandled action type: ${action.type}`);
  }

useReducer 사용하기

function Users() {
	// reducer 함수의 전달과 초기상태를 정의합니다.
  const [state, dispatch] = useReducer(reducer, {
    loading: false,
    data: null,
    error: null
  });

  const fetchUsers = async () => {
		//시작할 때 로딩중인 상태를 만들어줍니다.
    dispatch({ type: 'LOADING' });
    try {
      const response = await axios.get(
        'https://jsonplaceholder.typicode.com/users'
      );
      dispatch({ type: 'SUCCESS', data: response.data });
    } catch (e) {
      dispatch({ type: 'ERROR', error: e });
    }
  };

  useEffect(() => {
    fetchUsers();
  }, []);

  // state.data 를 users 키워드로 조회
  const { loading, data: users, error } = state;

  if (loading) return <div>로딩중..</div>;
  if (error) return <div>에러가 발생했습니다</div>;
  if (!users) return null;
  return (
    <>
      <ul>
        {users.map(user => (
          <li key={user.id}>
            {user.username} ({user.name})
          </li>
        ))}
      </ul>
      <button onClick={fetchUsers}>다시 불러오기</button>
    </>
  );
}

이렇게 useReducer를 통한 구현이 완료되었습니다.

axios Interceptors

실제로 API 호출을 하다 보면 요청이 실패하는 일도 생길 것 입니다.

바로 error를 띄워줘도 무방하지만 시간 간격을 두고 3번정도는 retry를 하고 그래도 안된다면 error를 띄워주고 싶다면 어떻게 해야 할까요?

Axios 라이브러리를 이용해서 서버에 Rest API 요청을 보내거나 응답을 받는 과정에서 가로채어 일을 처리할 수 있는 Interceptors에 대해 알아보겠습니다.

기본 예제

import axios from 'axios';

const onFulfilled = (response) => {
    // HTTP status가 2XX일 때 처리하고 싶은 로직이 있다면 여기에서 처리함
		// 데이터 받기에 성공했으므로 받은 response를 그대로 return 해준다.
		// 물론 따로 가공해도 됩니다.
    return response;
};
const onRejected = (error) => {
    // HTTP status가 2XX이 아닐 때 여기를 통과하게 됨
    // return은 항상 Promise.reject(error)로 해야함
    return Promise.reject(error);
};
axios.interceptors.response.use(onFulfilled, onRejected);

import axios from 'axios';
const customAxiosInstance = () => {
    const axiosInstance = axios.create();
    const onFulfilled = (response) => response;
    const retry = (errorConfig) => {
        return new Promise((resolve) => {
            setTimeout(() => {
                console.log('retry');
                resolve(axiosInstance.request(errorConfig));
            }, 5000);
        });
    }
    const onRejected = (error) => {
        if (error.config) {
            return retry(error.config);
        }
        
        return Promise.reject(error);
    };
    axiosInstance.interceptors.response.use(
        onFulfilled,
        onRejected,
    );
    return axiosInstance;
};
try {
    const apiRequest = customAxiosInstance();
    const response = await apiRequest.get(API_URL);
} catch {
}

apiRequest가 진행된 후 실패하면 error.config를 다시 담아 5초 뒤에 한 번 더 실행하는 retry 코드

예제코드에 적용시켜보기!

const fetchUsers = async () => {
    try {
      dispatch({ type: 'LOADING' });
      console.log('첫 API 호출이 되었습니다');
      const apiRequest = customAxiosInstance();
      const response = await apiRequest.get('https://jsonplaceholder.typicode.com/users');
      dispatch({ type: 'SUCCESS', data: response.data });
    } catch (e) {
      dispatch({ type: 'ERROR', error: e });
    }
  };

추가 예시 살펴보기


https://velog.io/@subanggu/axios-interceptor-적용하기

참고자료


https://react.vlpt.us/integrate-api/01-basic.html

https://flyingsquirrel.medium.com/api-fetch-retry로직-작성해보기-with-axios-5cb81e6345ad

https://이듬.run/axios/guide/api.html#http-메서드-별칭

0개의 댓글