프론트엔드 개발을 하다 보면 “서버에서 데이터를 어떻게 가져오고 관리할 것인가?”라는 고민을 반드시 하게 된다.
이 글에서는 기존 방식(useEffect 기반)부터 axios, fetch, 그리고 요즘 실무에서 많이 사용하는 TanStack Query까지 흐름 중심으로 정리한다.
가장 기본적인 데이터 요청 방식은 useEffect를 사용하는 것이다.
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch('/api/cafes')
.then(res => res.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, []);
👉 즉, 규모가 커질수록 코드가 지저분해지고 관리가 어려워진다
브라우저에 내장된 기본 HTTP 요청 API
const res = await fetch('/api/cafes');
const data = await res.json();
res.json())res.ok 확인 필요)HTTP 요청을 더 편하게 해주는 라이브러리
const { data } = await axios.get('/api/cafes');
| 항목 | fetch | axios |
|---|---|---|
| 설치 | ❌ 필요 없음 | ✅ 필요 |
| JSON 변환 | 수동 | 자동 |
| 에러 처리 | 불편 | 편함 |
| 인터셉터 | 없음 | 있음 |
| 사용성 | 기본 | 편리 |
👉 결론:
서버 데이터를 가져오고, 캐싱하고, 관리까지 자동으로 해주는 라이브러리
useEffect(() => {
fetch(...).then(...)
}, []);
const { data, isLoading, error } = useQuery({
queryKey: ['cafes'],
queryFn: () => fetch('/api/cafes').then(res => res.json()),
});
👉 UX 속도 향상
👉 항상 최신 데이터 유지
data
isLoading
error
👉 useState 필요 없음
👉 구조가 훨씬 깔끔해짐
👉 복잡한 기능도 쉽게 구현 가능
👉 이 둘을 분리하는 것이 현대 프론트엔드 핵심 구조
TanStack Query + fetch
TanStack Query + axios
| 상황 | 추천 |
|---|---|
| 간단한 프로젝트 | fetch |
| 일반적인 React 프로젝트 | fetch + TanStack Query |
| 인증/토큰/복잡 API | axios + TanStack Query |
요즘 프론트엔드는 “데이터 요청”이 아니라
“서버 상태 관리”를 한다
👉 그리고 그 중심이 바로 TanStack Query이다.