[REACT] axios

boyon99·2023년 7월 19일
0

react

목록 보기
10/10
post-thumbnail

axios

axios는 npm 을 통해서 설치해야 하는 모듈로 자바스크립트 내장 fetch 와 마찬가지로 promise 객체를 기반으로 통신을 처리한다.

  • json 변환을 자동으로 처리 (request.json()할 필요 없이 바로 data 프로퍼티에 접근 가능)
  • 요청에 대한 timeout 기능이 존재 (응답이 오기까지 대기할 최대 시간을 설정할 수 있음)
  • 요청 및 응답에 대한 인터셉트 기능 존재 (기본적으로 요청을 보내기 전 혹은 응답을 받은 후 실행될 코드를 지정해놓을 수 있음)

형식

axios.메소드(서버 URL 주소, 요청 데이터)의 형식으로 구성되어 axios.get / axios.post 와 같이 작성해서 요청을 보낼 수도 있고

axios({각종 옵션들, url 주소, 요청 데이터 등})

axios 라고만 작성하고 옵션을 모두 매개변수 인자로 넘기는 방식으로도 작성할 수 있다. 중요한 옵션은 아래와 같다.

axios({
	url: "서버주소",
  method: "get", // POST, PUT, DELETE 등의 요청 유형 선택
  headers: {
    Authorization: 인증 토큰 등
  },
  data: 리퀘스트 데이터 // POST, PUT 요청의 경우 전송 가능
});

응답

axios 함수가 실행되면 해당 서버 주소로 요청을 보내고 (프로미스 객체 반환), 그 요청이 완료되면, 해당 서버의 응답을 반환한다.

이 응답에는 다음과 같은 프로퍼티가 있다.

  • status - HTTP 상태 코드 (200~299 사이면 요청 성공, 400~500 사이라면 요청 실패)
  • statusText - 서버에서 전달된 상태 메세지 (ok 등이 올 수 있음)
  • headers - 응답의 헤더 부분
  • request - 응답을 생성한 request
  • data - 응답의 데이터가 담긴 부분
  • config - axios 자체의 설정

프로미스와 async/await

특정한 코드의 동작이 완료될 때까지 기다렸다가 다음 작업을 진행하도록 도와주는 것이 바로 promise 객체로, 특정한 코드의 수행이 완료되면 그 수행이 성공했는지 실패했는지에 따라서 다른 값을 반환해주는 객체이다.

promise
  .then((result) => {
    // 코드가 성공적으로 수행 완료될 경우 실행될 코드를 명시
    // 성공한 결과값 (result = 응답, 데이터) 를 활용할 수 있음
  })
  .catch((error) => {
    // 코드의 수행이 실패한 경우 실행될 코드를 명시
    // 에러 객체 (error) 를 활용할 수 있음
  });

axios 함수는 프로미스 객체를 반환하므로 then, catch 문법을 사용할 수 있다.

axios.get('서버url')
  .then(response => {요청 성공 시 실행할 코드})
  .catch(error => {에러 핸들링})

가독성을 고려할 때는 async/await를 사용하는 것이 더 좋다.

async/await 문법은 promise.then / catch 를 사용하지 않고도 프로미스를 처리할 수 있게 해준다. 또한await는 async 함수 안에서만 동작하며 사용 시 프로미스 객체가 처리될 때까지 기다렸다가 result에 결과값을 할당한다.

await 는 프로미스가 연달아 이어지는 상황에서도 코드가 깔끔하게 유지된다는 점에서 유용하다.

const getData = async () => {
  const response = await axios.get("서버주소"); // 응답이 올때까지 기다렸다가 response 에 저장
  // 여기서부터는 response 를 동기적으로 사용할 수 있게 됨
};

async/await 구문에서 에러 핸들링을 시 try catch 구문을 사용해야 한다.

const getData = async () => {
  try {
    const response = await axios.get("서버주소");
    // 응답과 관련한 코드
  } catch (err) {
    // 위에서 발생한 에러를 전부 여기서 처리
  }
};

요청하기

GET 요청

const getPosts = async () => {
  const response = await axios.get(
    "https://jsonplaceholder.typicode.com/posts"
  );
  console.log(response.data); // .data 라고 해야 데이터에 접근
};

// or
const getPosts = async () => {
  const response = await axios.get(`/posts`, {
    params: { userId: 1 },
  });
  return response.data;
};

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

POST 요청

const createPost = async (post) => {
  const response = await axios.post(
    `https://jsonplaceholder.typicode.com/posts`,
    post
  );
};

useEffect(() => {
  createPost({ title: "제목", body: "내용" });
}, []);

PUT 요청

put, patch method 는 이미 있는 데이터를 수정하기 위해서 보내는 요청으로 post와 동일하게 작성하되 데이터 수정 시 정확히 서버에 있는 어떤 데이터를 수정하고자 하는 것인지를 명시해서 보내야 한다.

const updatePost = async (post, id) => {
  const response = await axios.put(
    `https://jsonplaceholder.typicode.com/posts/${id}`,
    post
  );
  console.log(response.data);
};

useEffect(() => {
  updatePost({ title: "글 수정하기", body: "수정된 내용" }, 1);
}, []);

DELETE 요청

const deletePost = async (id) => {
  const response = await axios.delete(
    `https://jsonplaceholder.typicode.com/posts/${id}`
  );
  console.log(response.data);
};

useEffect(() => {
  deletePost(1);
}, []);

Axios 설정하기

config 옵션을 하나하나 명시하는 방식으로 아래와 같이 수정할 수 있다.

const createPost = async (post) => {
  const response = await axios({
    url: `https://jsonplaceholder.typicode.com/posts`,
    method: "post", // get, put, delete 등의 method 를 명시
    data: post,
  });
  return response.data;
};

timeout과 에러 핸들링을 할 수 있다.

const createPost = async (post) => {
  try {
    const response = await axios({
      url: `https://jsonplaceholder.typicode.com/posts`,
      method: "post", // get, put, delete 등의 method 를 명시
      data: post,
      timeout: 1, // 밀리초 단위 (명시한 시간 안에 요청이 안오면 시간초과 발생)
    });
    return response.data;
  } catch (err) {
    console.log(err);
  }
};;

config 기본값 지정할 수 있다.

// utils/axiosConfig.js
import axios from "axios";

export const axiosSocket = axios.create({
  baseURL: "또 다른 서버 주소",
});
export const axiosAPI = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com",
});
import { axiosAPI } from "../utils/axiosConfig";

const createPost = async (post) => {
  const response = await axiosAPI.post(`/posts`, post);
  return response.data;
};

환경변수를 지정할 수 있다.

//
VITE_SERVER_URL = "https://jsonplaceholder.typicode.com";
export const axiosAPI = axios.create({
  baseURL: import.meta.env.VITE_SERVER_URL,
});

인터셉터를 활용할 수 있다.

인터셉터는 요청 혹은 응답을 보내는 과정에서 요청 혹은 응답을 가로채고 특정한 작업을 수정하기 위한 기능으로 request response를 다룰 수 있다. 보통은 request 를 보낼 때에는 유저 인증 정보 존재 여부에 따라 유저 인증 정보를 요청에 포함시키기 위해 사용하고, response 를 받을 때에는 데이터 파싱 등을 처리하기 위해 사용한다.

axios.interceptors.request.use(
  (request) => {
    console.log(request);
    return request;
  },
  (error) => {
    console.log(error);
    return Promise.reject(error);
  }
);
axios.interceptors.response.use(
  (response) => {
    if (response.status === 200 || response.status === 201) {
      return response.data;
    }
    return response;
  },
  (error) => {
    console.log(error);
    return Promise.reject(error);
  }
);

더 많은 요청 config를 확인할 수 있다.

Axios 더 깊이 활용해보기

params 전달하기

api 에 따라, 조건을 걸어서 데이터를 가져오는 것이 가능하다.

const getPosts = async () => {
  const response = await axios.get(`/posts`, {
    params: { userId: 1 },
  });
  return response.data;
};

파라미터가 복잡해지는 경우 qs 모듈을 사용할 수 있다.

객체가 중첩되는 형태로 params를 작성하는 경우 아래처럼 설정해야 한다.

yarn add qs
// main.jsx
import qs from "qs";

axios.defaults.paramsSerializer = {
  serialize: (params) => Qs.stringify(params, { arrayFormat: "brackets" }),
};

로딩/에러 관리하기

import React, { useEffect, useState } from "react";
import axios from "axios";

function Example() {
  const [posts, setPosts] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const getPosts = async () => {
    try {
      setIsLoading(true);
      const response = await axios.get(`/posts`, {
        params: { userId: 1 },
      });
      return response.data;
    } catch (err) {
      setError(err);
    }
  };
  const setPostsByResponse = async () => {
    const data = await getPosts();
    setPosts(data);
    setIsLoading(false);
  };

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

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>{error.message}</div>;
  return (
    <div>
      {posts.map((post) => {
        return (
          <div key={post.id}>
            <h1>{post.title}</h1>
            <p>작성자: {post.userId}</p>
            <p>{post.body}</p>
          </div>
        );
      })}
    </div>
  );
}

export default Example;

axios 요청을 위한 커스텀 훅 만들어보기 (useAsync)

// hooks/useAsync.jsx
import { useEffect, useState } from "react";

function useAsync(callback, args) {
  const [data, setData] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const fetchData = async () => {
    try {
      setIsLoading(true);
      const responseData = await callback(args);
      setData(responseData);
    } catch (err) {
      setError(err);
    }
    setIsLoading(false);
  };

  useEffect(() => {
    fetchData();
  }, [args]);

  return { data, isLoading, error };
}

export default useAsync;
// example.jsx
import React, { useEffect, useRef, useState } from "react";
import axios from "axios";
import useAsync from "../hooks/useAsync";

function Example() {
  const inputRef = useRef(1);
  const [postId, setPostId] = useState(1);

  const getPost = async (id) => {
    const response = await axios.get(`/posts/${id}`);
    return response.data;
  };
  const { isLoading, data: post, error } = useAsync(getPost, postId);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>{error.message}</div>;
  return (
    <div>
      <input ref={inputRef}></input>
      <button onClick={() => setPostId(inputRef.current.value)}>검색</button>
      <div key={post.id}>
        <h1>
          {post.id}번 글: {post.title}
        </h1>
        <p>작성자: {post.userId}</p>
        <p>{post.body}</p>
      </div>
    </div>
  );
}

export default Example;

0개의 댓글

관련 채용 정보