Axios 사용법: React Next.js에서 API 요청 구조 잡는 법

2025.12.05·수정 2026.09.12·약 14분·작성: 해비·블로그 소개

실습 경로: 현재 ZIP전체 코드. 먼저 설명에서 지정한 파일만 읽고, 설정·테스트 파일은 필요한 때 확인하세요.

목표: Axios 인스턴스·HTTP 오류·취소를 React의 로딩 상태와 연결합니다. 선수 지식은 Promise, HTTP, React Effect입니다.

Axios와 fetch를 요구에 따라 선택합니다

Axios는 HTTP 요청 라이브러리입니다. 인스턴스 공통 설정과 인터셉터가 필요한 프로젝트에서 사용할 수 있으며 React·Next.js에 필수인 패키지는 아닙니다. Next.js 서버 fetch의 캐시 옵션은 Axios에 자동 적용되지 않습니다. TanStack Query는 서버 상태 관리 도구로 Axios 또는 fetch와 별도로 선택합니다.

응답과 오류의 구조를 구분합니다

Axios의 response.data는 응답 본문이고 status는 상태 코드입니다. 기본 validateStatus는 2xx를 성공으로 보지만 이를 변경하면 404도 resolve할 수 있습니다. axios.isAxiosError로 좁힌 뒤 response가 있으면 HTTP 응답, request만 있으면 응답 미수신, 그 밖에는 설정·코드 오류를 살펴봅니다. 브라우저 CORS 차단과 서버 중단은 error.message만으로 확정할 수 없습니다.

하나의 인스턴스에서 조회 함수를 만듭니다

lib/api.ts는 브라우저의 같은 출처 /api를 baseURL로 사용합니다. 상대 baseURL을 그대로 Node.js에서 호출하는 독립 스크립트에 복사하지 마세요. 서버에서 사용하려면 서버용 절대 URL과 인증 전달 정책을 따로 만듭니다. 이 실습에는 토큰 주입이 필요하지 않습니다. 공용 테스트 API에 실제 토큰을 보내는 인터셉터를 작성하지 않습니다.

Effect 종료 시 취소와 UI 갱신을 함께 막습니다

아래 전체 프로젝트는 1번·2번·없는 글을 선택합니다. 선택이 바뀌면 새 AbortController를 만들고 이전 Effect의 active를 false로 바꾼 뒤 abort합니다. 이미 완료된 Promise callback이 늦게 실행되더라도 이전 결과가 현재 화면을 덮지 않게 합니다. 이전 요청의 finally가 새로운 로딩 상태를 끄는 패턴은 쓰지 않습니다.

취소는 사용자에게 실패 오류로 표시하지 않습니다. CancelToken은 deprecated이므로 새 예제는 signal을 사용합니다. abort는 클라이언트의 대기를 취소하며 이미 서버에서 처리한 저장 작업을 되돌리는 트랜잭션은 아닙니다.

직접 확인할 결과

npm install, npm run build, npm run start 후 /를 엽니다. 1은 첫 글, 2는 둘째 글, 99는 글이 없습니다가 기대 결과입니다. Network에서 느린 연결로 바꾸고 빠르게 1→2를 선택해 오래된 응답이 화면을 되돌리지 않는지 보세요. 연결을 끊으면 일반 오류가 표시되어야 합니다. 이 브라우저 조작은 별도 확인 과제이며 로컬 HTTP 응답 검사와 구분합니다.

POST와 인터셉터로 확장할 때

api.post(‘/posts’, values)는 서버 POST 구현이 있을 때 추가합니다. 현재 실습은 읽기 전용이므로 POST는 405가 정상입니다. JSONPlaceholder 같은 공개 모의 API의 성공 응답은 실제 저장을 뜻하지 않습니다. 인터셉터를 컴포넌트에서 등록한다면 반환 ID를 보관해 cleanup에서 eject해야 중복 등록을 피할 수 있습니다. 401 자동 갱신은 재시도 횟수와 동시 요청을 별도로 설계합니다.

Axios 사용법: React Next.js에서 API 요청 구조 잡는 법 핵심 개념을 설명하는 첫 번째 본문 이미지Axios 사용법: React Next.js에서 API 요청 구조 잡는 법 적용 흐름을 설명하는 두 번째 본문 이미지Axios 사용법: React Next.js에서 API 요청 구조 잡는 법 참고 내용을 설명하는 본문 이미지 3Axios 사용법: React Next.js에서 API 요청 구조 잡는 법 참고 내용을 설명하는 본문 이미지 4Axios 사용법: React Next.js에서 API 요청 구조 잡는 법 참고 내용을 설명하는 본문 이미지 5

관련 학습 자료

현재 실습 ZIP

현재 본문과 같은 실습 파일 내려받기

전체 실행 파일

아래는 함께 실행하는 단일 완성 프로젝트입니다. ZIP을 풀고 프로젝트 폴더에서 npm install, npm run build, npm run start를 실행합니다. 개발은 npm run dev, 타입 검사는 npm run typecheck입니다. Node.js 20.9 이상, 검증 환경 Node.js 24.19.0 / Next.js 16.3.5 / React 19.3.0 / TypeScript 7.0.2입니다.

README.md

# Axios 요청과 취소

Node.js 20.9 이상(검증24.19.0). npm install → npm run build → npm run start. 개발은 npm run dev.
/ 화면에서 1·2·없는 글 선택. /api/posts/1·2는200, /api/posts/99는404. 저장·인증·외부 API 없음.
Axios 1.20.0, Next.js16.3.5, React19.3.0. 로컬 HTTP·build 검증, 브라우저 빠른 선택·네트워크 차단은 별도 확인.

app/PostPanel.tsx

"use client";
import { useEffect, useState } from "react";
import axios from "axios";
import { getPost, type Post } from "../lib/api";
type State =
  | { status: "loading" }
  | { status: "error"; message: string }
  | { status: "success"; post: Post };
export default function PostPanel() {
  const [id, setId] = useState(1);
  const [state, setState] = useState<State>({ status: "loading" });
  useEffect(() => {
    const controller = new AbortController();
    let active = true;
    setState({ status: "loading" });
    getPost(id, controller.signal)
      .then((post) => {
        if (active) setState({ status: "success", post });
      })
      .catch((error) => {
        if (!active || axios.isCancel(error)) return;
        const message =
          axios.isAxiosError(error) && error.response?.status === 404
            ? "글이 없습니다."
            : "요청에 실패했습니다.";
        setState({ status: "error", message });
      });
    return () => {
      active = false;
      controller.abort();
    };
  }, [id]);
  return (
    <section>
      <label>
        글 번호{" "}
        <select
          value={id}
          onChange={(event) => setId(Number(event.target.value))}
        >
          <option value={1}>1</option>
          <option value={2}>2</option>
          <option value={99}>없는 글</option>
        </select>
      </label>
      {state.status === "loading" ? (
        <p role="status">불러오는 중</p>
      ) : state.status === "error" ? (
        <p role="alert">{state.message}</p>
      ) : (
        <h2>{state.post.title}</h2>
      )}
    </section>
  );
}

app/api/posts/[id]/route.ts

export async function GET(
  _request: Request,
  { params }: { params: Promise<{ id: string }> },
) {
  const { id } = await params;
  if (!["1", "2"].includes(id))
    return Response.json({ message: "글이 없습니다." }, { status: 404 });
  return Response.json({
    id: Number(id),
    title: id === "1" ? "첫 글" : "둘째 글",
  });
}

app/layout.tsx

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body>{children}</body>
    </html>
  );
}

app/page.tsx

import PostPanel from "./PostPanel";
export default function Page() {
  return (
    <main>
      <h1>Axios 요청과 취소</h1>
      <PostPanel />
    </main>
  );
}

lib/api.ts

import axios from "axios";
export const api = axios.create({ baseURL: "/api", timeout: 5000 });
export type Post = { id: number; title: string };
export async function getPost(id: number, signal: AbortSignal) {
  const response = await api.get<Post>("/posts/" + id, { signal });
  return response.data;
}

next-env.d.ts

/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
import "./.next/types/root-params.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

package.json

{
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build --webpack",
    "start": "next start",
    "typecheck": "next typegen && tsc --noEmit"
  },
  "engines": {
    "node": ">=20.9.0"
  },
  "dependencies": {
    "next": "16.3.5",
    "react": "19.3.0",
    "react-dom": "19.3.0",
    "axios": "1.20.0"
  },
  "devDependencies": {
    "typescript": "7.0.2",
    "@types/react": "19.3.0",
    "@types/react-dom": "19.3.0",
    "@types/node": "22.20.2"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "esnext"],
    "strict": true,
    "skipLibCheck": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "plugins": [
      {
        "name": "next"
      }
    ],
    "allowJs": true,
    "incremental": true
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts",
    ".next/dev/types/**/*.ts"
  ],
  "exclude": ["node_modules"]
}

실제 검증: next build exit 0; 로컬 API 1·2 200/없는글404/POST405 확인. 브라우저 취소 경합은 확인 과제. 코드 뷰어와 ZIP의 모든 파일을 바이트/복사 텍스트로 대조했습니다.

공식 자료 재확인: 2026-09-12. 이 글의 실행하지 않은 브라우저/배포 점검은 독자 확인 과제로 구분합니다.

이 글이 도움이 되었나요?

조회 중

Next.js 학습 순서

필수 13개 · 전체 27개

읽음 기록 관리

전체 과정 목차 (27개)
  1. 필수 길잡이 · Next.js App Router 학습 순서: 설치부터 배포까지
  2. 필수 학습 · Next.js package.json: scripts dependencies 이해
  3. 필수 학습 · Next.js App Router로 만드는 첫 프로젝트 완성 실습 가이드
  4. 필수 학습 · Next.js에서 .next 폴더는 어떤 역할을 할까?
  5. 필수 학습 · Next.js 동적 라우트 완전 정리: [slug], params, catch-all
  6. 선택 참고 · Next.js params should be awaited 해결: App Router 기준
  7. 선택 참고 · Next.js window is not defined 오류 해결: 브라우저 API를 안전하게 쓰기
  8. 선택 참고 · Next.js hydration failed 오류 해결: 원인과 해결 방법
  9. 필수 학습 · Axios 사용법: React Next.js에서 API 요청 구조 잡는 법 현재 글
  10. 선택 참고 · Next.js Route Handler 405 오류 해결: GET/POST 파일 위치와 메서드 설정 확인
  11. 필수 학습 · Next.js Server Actions + React Hook Form 검증 기준
  12. 선택 참고 · Next.js useSearchParams Suspense 오류 해결: 빌드 실패 기준
  13. 선택 참고 · Next.js fetch 캐시 문제 해결: 데이터가 바뀌었는데 화면이 그대로일 때
  14. 선택 참고 · Next.js Dynamic server usage 오류 해결: cookies headers 기준
  15. 선택 참고 · Next.js 환경변수 적용 오류 해결: .env.local을 바꿨는데 값이 안 바뀔 때
  16. 필수 학습 · Next.js Metadata API 완전 정리: 정적 metadata와 generateMetadata
  17. 선택 참고 · Next.js metadata가 적용되지 않을 때 확인할 7가지
  18. 선택 참고 · Next.js Image remotePatterns 오류 해결: 외부 이미지 도메인 허용하기
  19. 필수 학습 · Next.js redirects 설정: next.config.js에서 URL 이동 처리
  20. 필수 학습 · Next.js SEO 체크리스트: metadata·초기 HTML·OG 이미지 점검
  21. 선택 참고 · Next.js SEO 완전 가이드: App Router metadata부터 배포 확인까지
  22. 필수 학습 · Next.js 16 성능 최적화 체크리스트: 번들·이미지·캐시·배포
  23. 필수 학습 · Next.js 렌더링 성능 최적화: React 화면이 느릴 때 기준
  24. 필수 학습 · Next.js 16 Proxy 마이그레이션: Node.js Runtime·matcher 검증
  25. 선택 참고 · Next.js 보안 패치 기준: v16.2.5 영향 범위 점검
  26. 선택 참고 · Next.js SEO SSR 적용법: 검색 노출과 렌더링 구조 잡기
  27. 시점·기록 · Next.js 16.3.0-canary.106의 useCache deprecation 경고와 hybrid not-found 수정 이해하기

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기