Axios와 async/await를 활용한 비동기 통신 정리
Axios란?
Axios는 Node.js와 브라우저 모두에서 사용할 수 있는 Promise 기반의 HTTP 클라이언트
동일한 코드로 브라우저와 Node.js 환경에서 모두 작동할 수 있는 동형(isomorphic) 라이브러리
- 서버 사이드에서는 Node.js의 http 모듈을 사용
- 클라이언트(브라우저)에서는 XMLHttpRequest를 이용해 요청
설치 방법
npm install axios
동기(Synchronous) vs 비동기(Asynchronous)
프로그래밍에서는 작업이 실행되는 방식에 따라 **동기(Sync)**와 **비동기(Async)**로 나눌 수 있습니다.
동기(Synchronous)
- 순차적으로 작업이 실행
- 이전 작업이 끝나야 다음 작업이 실행
- setState 호출 → 이전 상태 업데이트가 완료되어야 다음 로직이 실행
console.log("1");
console.log("2");
console.log("3");
// 출력: 1 → 2 → 3 (순차적 실행)
비동기(Asynchronous)
- 작업이 완료되지 않아도 다음 코드가 실행
- axios와 같은 HTTP 요청, setTimeout 등이 대표적
console.log("1");
setTimeout(() => console.log("2"), 1000);
console.log("3");
// 출력: 1 → 3 → 2 (비동기 실행)
주의할 점
axios 같은 비동기 요청은 응답이 도착하기 전에 다음 코드가 실행될 수 있어 의도와 다른 결과가 발생 가능성 ⬆️
이를 해결하기 위해 사용하는 것이 바로 async/await 문법
기본적인 Axios 사용법 (Promise 방식)
비동기적으로 데이터 요청
<script>
const API_BASE_URL = "http://~:8080/eureka/book";
function fetchData() {
axios
.get(API_BASE_URL) // 비동기 요청
.then((response) => {
// 요청이 완료된 후 실행됨
const books = response.data.books;
const result = document.getElementById("result");
if (!Array.isArray(books) || books.length === 0) {
result.innerHTML = "<h1>도서 정보가 없습니다.</h1>";
return;
}
const html = books
.map((book) => `<div class='book'>${JSON.stringify(book)}</div>`)
.join();
result.innerHTML = html;
})
.catch((error) => {
// 에러 처리
console.log(error);
result.innerHTML = "<h1>오류발생</h1>";
});
}
</script>
특징
- .then()으로 요청 완료 후 결과 처리
- .catch()로 에러 처리
- 단점: 중첩되면 콜백 지옥처럼 보일 수 있고, 가독성이 떨어짐
async/await 문법으로 더 깔끔하게!
async/await을 활용한 동일 기능
<script>
async function fetchData() {
const resultEl = document.getElementById("result");
const API_BASE_URL = "~0/eureka/book";
resultEl.innerHTML = "로딩 중...";
try {
// await: axios 응답이 완료될 때까지 기다림
const response = await axios.get(API_BASE_URL);
const books = response.data.books;
if (!Array.isArray(books) || books.length === 0) {
resultEl.innerHTML = "<h1>도서 정보가 없습니다.</h1>";
return;
}
const html = books
.map((book) => `<div class='book'>${JSON.stringify(book)}</div>`)
.join();
resultEl.innerHTML = html;
} catch (error) {
// 에러는 try-catch로 처리
console.error(error);
resultEl.textContent = "오류 발생: " + error;
}
}
</script>
특징
- await는 해당 비동기 작업이 완료될 때까지 기다린다
- try/catch 문으로 에러 처리가 더 명확하고 직관적
비동기 함수는 useCallback / useEffect와 함께!
: React에서는 비동기 함수를 컴포넌트에서 사용할 때 useCallback, useEffect 등과 함께 사용
const searchAllBooks = useCallback(async () => {
// 비동기 요청 코드
}, []);
=> 리렌더링마다 함수를 새로 만들지 않도록 useCallback을 사용
처음 마운트 시 API 요청 | useEffect | 언제 실행할지 제어 (의존성 배열로) |
버튼 클릭 시 API 요청 | useCallback | 함수 재생성 방지, 성능 최적화 |
렌더링 중 비동기 호출 방지 | useEffect or useCallback | React 렌더링 규칙 지키기 위해 |
배열 형태의미
[] | 딱 한 번만 실행 (처음 마운트 시) |
[a] | a가 바뀔 때마다 실행 or 재생성 |
[a, b] | a 또는 b가 바뀔 때마다 실행 or 재생성 |
공통 설정이 반복될 때 – Axios 인스턴스 만들기
import axios from "axios";
const BASE_URL = "http://~.8080/eureka/";
// 공통 설정을 포함한 axios 인스턴스
function localAxios() {
const instance = axios.create({
baseURL: BASE_URL,
headers: {
"Content-Type": "application/json;charset=utf-8",
},
});
return instance;
}
export { localAxios };
const axios = localAxios();
=> localAxios()를 통해 만든 인스턴스를 사용
공통 에러 핸들링 함수로 추출하기
=> 공통 로직은 분리하고, UI와 비즈니스 로직은 각각 나눠서 관리!!!
비슷한 패턴의 try/catch 구문을 반복적으로 작성하는 대신 에러 핸들링 로직을 공통화
export const handleApi = async <T>(fn: () => Promise<T>) => {
try {
const data = await fn();
return { data, error: null };
} catch (error) {
let msg = "";
if (error instanceof Error) {
msg = error.message;
} else {
msg = "오류가 발생했습니다.";
}
return { data: null, error: msg };
}
};
=> handleApi 유틸 함수를 이용하면, 비동기 데이터 요청을 더욱 깔끔하게 관리
const loadBooks = useCallback(
async (params: BookSearchParams = {}) => {
setLoading(true); // 로딩 상태 true로 설정
const { data, error } = await handleApi(() => searchAllBooks(params));
// handleApi를 통해 에러와 데이터를 동시에 받아옴
if (error) {
setError(error); // 에러 발생 시 에러 상태 업데이트
} else if (data) {
setBook(data); // 정상적으로 데이터가 올 경우 상태에 저장
}
setLoading(false); // 로딩 완료 처리
},
[]
);
'React' 카테고리의 다른 글
Context 알아보기 (0) | 2025.04.22 |
---|---|
TanStack Query (React Query) 알아보기 (0) | 2025.04.21 |
React & Next.js 활용해보기 / CSR vs SSR (1) | 2025.04.14 |
React TypeScript 활용해보기 (1) | 2025.04.11 |
SCSS와 SASS: 효율적인 CSS 전처리기 사용법 (0) | 2025.04.08 |