티스토리 뷰
React로 화면을 만들다 보면 결국 한 번은 API 연동에서 막히게 됩니다. 목록 데이터를 가져와서 화면에 뿌리는 GET 요청도 필요하고, 사용자가 입력한 값을 서버로 보내는 POST 요청도 필요하기 때문입니다. 그런데 처음에는 어디서 GET을 써야 하는지, POST는 어떻게 보내는지, 성공 후 화면은 어떻게 다시 갱신해야 하는지 흐름이 잘 안 잡히는 경우가 많습니다.
입문 예제에서는 fetch를 많이 쓰지만, 실제 실무에서는 Axios를 더 자주 선택하는 경우가 많습니다. 기본 URL 관리, 요청/응답 공통 처리, 인터셉터, 타임아웃 설정 같은 부분을 한 곳에서 정리하기 더 편하기 때문입니다.
그래서 이 글에서는 단순히 "데이터를 받아온다" 수준에서 끝내지 않고, React에서 Axios로 GET 요청과 POST 요청을 처리하는 기본 흐름, 그리고 실무에서 자주 막히는 포인트까지 같이 정리해보겠습니다.
쉽게 말하면 React API 연동은 브라우저 화면이 서버에 요청을 보내고, 서버 응답을 상태에 저장한 뒤, 그 결과를 사용자 화면에 반영하는 작업입니다.
예를 들어 게시글 목록을 불러올 때는 GET 요청을 보내고, 새 게시글을 등록할 때는 POST 요청을 보냅니다. 그래서 React에서는 보통 아래 두 흐름을 함께 이해해야 합니다.
GET 요청 흐름
컴포넌트 렌더링
↓
API 요청 시작
↓
응답 수신
↓
state 저장
↓
화면 다시 렌더링
POST 요청 흐름
사용자 입력
↓
버튼 클릭 또는 폼 제출
↓
API 요청 시작
↓
응답 수신
↓
성공 메시지 / 목록 갱신 / 입력 초기화
React API 연동의 핵심은 서버와 화면 상태를 연결하는 것입니다. GET만 알아도 부족하고, POST 이후 화면을 어떻게 바꿀지도 같이 알아야 합니다.
정리하면 fetch가 나쁘다는 뜻은 아닙니다. 다만 화면이 늘어나고, GET과 POST 요청이 많아지고, 로그인 토큰 처리나 공통 에러 처리가 필요해지면 Axios 쪽이 구조를 잡기 더 편한 경우가 많습니다.
- 여러 API 엔드포인트를 계속 호출해야 할 때
- 공통 base URL과 headers를 한 번에 관리하고 싶을 때
- GET, POST, PUT, DELETE 요청을 일관된 방식으로 다루고 싶을 때
- 401/500 에러를 공통으로 처리하고 싶을 때
1. Axios 설치하기
먼저 프로젝트에 Axios를 설치합니다.
npm install axios
2. GET 요청으로 목록 데이터 가져오기
아래 예제는 테스트 API에서 게시글 목록을 받아와 화면에 출력하는 가장 기본적인 형태입니다.
import { useEffect, useState } from 'react';
import axios from 'axios';
function PostList() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
useEffect(() => {
const fetchPosts = async () => {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
setPosts(response.data.slice(0, 5));
} catch (err) {
setError('데이터를 불러오지 못했습니다.');
} finally {
setLoading(false);
}
};
fetchPosts();
}, []);
if (loading) return <p>로딩 중...</p>;
if (error) return <p>{error}</p>;
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
export default PostList;
이 코드는 구조가 단순하지만, 실무에서 필요한 핵심이 다 들어 있습니다.
- 컴포넌트가 처음 렌더링될 때 GET 요청 실행
- 로딩 상태 분리
- 에러 상태 분리
- 성공 시 받은 데이터 저장
map()으로 화면 출력
3. GET 요청 흐름을 눈으로 이해하기
처음 렌더링
↓
useEffect 실행
↓
axios.get 요청
↓
성공: setPosts(response.data)
실패: setError(...)
↓
loading false 처리
↓
화면 다시 렌더링
GET 요청은 보통 화면 진입 시 데이터를 보여줘야 하므로 `useEffect` 안에서 처리하는 경우가 많습니다.
1. POST 요청은 보통 이벤트에서 보낸다
POST 요청은 화면이 열리자마자 자동으로 보내는 경우보다, 사용자가 버튼을 누르거나 폼을 제출했을 때 실행하는 경우가 많습니다.
아래 예제는 제목과 내용을 입력받아 서버로 전송하는 기본 형태입니다.
import { useState } from 'react';
import axios from 'axios';
function PostForm() {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const [message, setMessage] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post('https://jsonplaceholder.typicode.com/posts', {
title,
body,
userId: 1,
});
console.log(response.data);
setMessage('등록이 완료되었습니다.');
setTitle('');
setBody('');
} catch (err) {
setMessage('등록에 실패했습니다.');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="제목 입력"
/>
<textarea
value={body}
onChange={(e) => setBody(e.target.value)}
placeholder="내용 입력"
/>
<button type="submit">등록</button>
<p>{message}</p>
</form>
);
}
export default PostForm;
2. POST 요청 후 무엇을 해야 할까?
POST 요청은 서버에 데이터를 보내는 것에서 끝나지 않습니다. 성공한 뒤 화면을 어떻게 바꿀지도 중요합니다.
보통은 아래 중 하나를 같이 처리합니다.
- 성공 메시지 출력
- 입력창 초기화
- 목록 다시 조회
- 상세 페이지 이동
- 모달 닫기
즉 실무에서는 POST 성공 이후의 UI 반응까지 포함해서 구현해야 진짜 완료라고 볼 수 있습니다.
3. GET과 POST를 같이 쓰는 흐름
처음 진입
↓
GET 요청으로 목록 조회
↓
사용자 입력
↓
POST 요청으로 데이터 등록
↓
성공 후 목록 재조회 또는 화면 갱신
이 패턴은 게시판, 댓글, 할 일 목록, 관리자 화면처럼 거의 모든 CRUD 화면의 기본 뼈대가 됩니다.
문제 1. API는 호출했는데 화면이 안 바뀌는 경우
이럴 때는 보통 setState가 안 되는 게 아니라, 렌더링할 때 참조하는 데이터 구조를 잘못 본 경우가 많습니다. 예를 들어 response.data가 배열인지 객체인지 먼저 확인해야 합니다.
console.log(response.data);
응답 구조를 확인하지 않고 바로 map()을 돌리면 posts.map is not a function 같은 오류가 자주 납니다.
문제 2. 무한 호출이 발생하는 경우
useEffect의 의존성 배열을 잘못 넣으면 GET 요청이 계속 반복 호출될 수 있습니다.
useEffect(() => {
fetchPosts();
}, []);
처음 한 번만 호출하려면 보통 빈 배열 []을 사용합니다. 반대로 검색어, 페이지 번호 같은 값이 바뀔 때마다 재호출해야 한다면 어떤 값이 의존성인지 명확하게 관리해야 합니다.
문제 3. POST는 성공했는데 목록이 그대로인 경우
이건 정말 자주 나옵니다. 서버에는 저장됐는데 화면은 예전 목록 그대로라서 사용자가 실패한 줄 아는 경우입니다.
이럴 때는 POST 성공 뒤 아래 중 하나를 해줘야 합니다.
- GET 요청을 다시 호출해서 목록 재조회
- 기존 state에 새 데이터를 직접 추가
- 상세 페이지 또는 완료 화면으로 이동
즉 POST는 요청 성공만 확인할 게 아니라 성공 이후 화면 갱신 전략까지 같이 설계해야 합니다.
문제 4. CORS 에러가 나는 경우
이건 React 문제가 아니라 브라우저 보안 정책과 서버 설정 문제인 경우가 많습니다. 프론트에서 아무리 코드를 바꿔도, 서버가 허용하지 않으면 요청이 막힐 수 있습니다.
즉 API 연동이 안 될 때는 프론트 코드만 볼 게 아니라 아래도 같이 봐야 합니다.
- API 서버의 CORS 허용 설정
- 요청 주소가 맞는지
- 프록시 설정이 필요한지
- 인증 토큰이 필요한지
- POST 요청이라면 Content-Type이 맞는지
문제 5. 매번 URL을 직접 적어서 관리가 지저분해지는 경우
실무에서는 API가 하나가 아니라 여러 개라서 매번 axios.get('https://...'), axios.post('https://...')를 흩어 써두면 관리가 빠르게 불편해집니다. 이런 경우 Axios 인스턴스를 분리해두면 훨씬 낫습니다.
import axios from 'axios';
export const api = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
},
});
그다음 컴포넌트에서는 더 짧게 사용할 수 있습니다.
const postsResponse = await api.get('/posts');
const createResponse = await api.post('/posts', {
title: '새 글',
body: '내용',
userId: 1,
});
- `axios` 설치가 정상적으로 되었는지 확인
- GET 요청은 `useEffect`, POST 요청은 이벤트 핸들러에 적절히 배치했는지 확인
- `response.data` 구조가 배열인지 객체인지 먼저 확인
- 로딩 상태와 에러 상태를 분리했는지 확인
- POST 성공 후 목록 갱신이나 입력 초기화가 필요한지 확인
- CORS, 토큰, 프록시, Content-Type 같은 연동 조건도 함께 확인
- GET은 보통 목록 조회, 상세 조회처럼 화면에 데이터를 보여줄 때 많이 씁니다.
- POST는 등록, 작성, 생성처럼 서버에 새 데이터를 보낼 때 많이 씁니다.
- 같은 API를 여러 화면에서 재사용한다면 Axios 인스턴스와 API 함수 파일을 분리하는 편이 좋습니다.
- 데이터 캐싱, 재요청, stale 관리까지 필요해지면 이후에는 TanStack Query 같은 도구를 검토하는 경우가 많습니다.
- 하지만 입문 단계에서는 도구를 늘리기보다 GET으로 가져오기 → POST로 보내기 → 성공 후 화면 갱신 흐름을 먼저 제대로 이해하는 게 더 중요합니다.
- GET은 데이터를 가져오는 요청, POST는 데이터를 등록하는 요청으로 먼저 구분하면 이해가 쉽습니다.
- GET 요청은 보통 `useEffect`에서, POST 요청은 `onClick`이나 `onSubmit` 같은 이벤트에서 처리합니다.
- POST 성공 후에도 화면이 자동으로 바뀌지 않을 수 있으니 목록 재조회나 state 갱신이 필요합니다.
- CORS 에러는 프론트 문법 문제가 아니라 서버 허용 설정 문제일 가능성이 큽니다.
- 실무에서는 공통 URL, 토큰, 에러 처리를 위해 Axios를 선호하는 경우가 많습니다.
- Q. React API 연동은 꼭 Axios로 해야 하나요?
→ 꼭 그렇지는 않습니다. 작은 예제는 fetch로도 충분합니다. 다만 실무에서는 GET, POST 요청이 많아지고 공통 설정이 필요해지기 때문에 Axios가 더 편한 경우가 많습니다. - Q. GET 요청과 POST 요청은 어디서 실행하는 게 좋나요?
→ 보통 GET 요청은 화면 진입 시 데이터가 필요하므로 `useEffect`에서 처리하고, POST 요청은 사용자 입력 후 버튼 클릭이나 폼 제출 이벤트에서 처리합니다. - Q. POST는 성공했는데 화면 목록이 그대로입니다.
→ 서버 저장과 화면 갱신은 별개입니다. POST 성공 후 GET 재호출, state 직접 추가, 페이지 이동 같은 후속 처리가 필요합니다. - Q. Axios 다음 단계로 많이 보는 도구는 무엇인가요?
→ 데이터 캐싱과 재요청 관리가 중요해지면 TanStack Query를 함께 쓰는 경우가 많습니다. 다만 먼저 Axios 기본 흐름부터 익히는 편이 좋습니다.
React에서 API를 연동할 때 핵심은 어렵지 않습니다.
- GET으로 데이터를 받아오고
- POST로 데이터를 보내고
- 로딩과 에러를 나눠서 처리하고
- 성공 후 화면을 다시 맞게 갱신하면 됩니다.
그런데 실제 프로젝트에서는 이 흐름이 반복되기 때문에, 공통 설정과 관리가 쉬운 Axios를 많이 선택하게 됩니다.
즉 이번 단계에서는 GET + POST + 화면 갱신 패턴을 먼저 익히고, 프로젝트가 커지면 Axios 인스턴스 분리나 TanStack Query까지 확장해나가면 됩니다.
React API 연동은 GET, POST 요청 문법을 외우는 것보다 요청 시점과 성공 후 화면 변화까지 같이 설계하는 순간부터 실무형 코드가 됩니다.
※ 이 글은 React 입문자 기준으로 GET 요청과 POST 요청 흐름을 함께 이해하기 위한 가이드입니다. 실제 운영 환경에서는 인증 토큰, 공통 에러 처리, 환경변수 분리, 캐싱 전략까지 함께 설계하면 더 안정적인 구조로 확장할 수 있습니다.
'Front > React' 카테고리의 다른 글
| React useState 사용법 정리 | 상태 관리, 값 변경, 배열·객체 업데이트까지 (0) | 2026.04.04 |
|---|---|
| React useEffect 사용법 정리 | 실행 시점, 의존성 배열, API 호출까지 (0) | 2026.04.03 |
| React 리눅스 서버 배포 방법 | build 파일 업로드부터 실제 서비스 적용까지 (0) | 2026.04.03 |
| React Router 사용법 | 페이지 이동, Link, 기본 라우팅 적용 방법 (2) | 2026.04.02 |
| React JSX 문법 정리 | 기본 문법, 조건부 렌더링, 리스트 렌더링까지 (0) | 2026.04.02 |

