시작 전 확인
두 서버가 모두 실행 중이어야 합니다:
- 프론트엔드:
http://localhost:5173(npm run dev) - 백엔드:
http://localhost:8000(uvicorn main:app --reload)
1 TanStack Query 설치
프론트엔드 폴더(my-admin)에서 실행하세요:
# my-admin 폴더에서 실행
npm install @tanstack/react-query src/main.tsx에 QueryClientProvider를 추가합니다:
import React from 'react'
import ReactDOM from 'react-dom/client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import App from './App'
import './index.css'
const queryClient = new QueryClient()
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>,
)2 API 클라이언트 생성
src/api/client.ts 파일을 만듭니다:
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
class ApiClient {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
async get<T>(path: string): Promise<T> {
const response = await fetch(`${this.baseUrl}${path}`);
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
return response.json() as Promise<T>;
}
async post<T, D>(path: string, data: D): Promise<T> {
const response = await fetch(`${this.baseUrl}${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
return response.json() as Promise<T>;
}
async delete(path: string): Promise<void> {
const response = await fetch(`${this.baseUrl}${path}`, {
method: 'DELETE',
});
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
}
}
export const apiClient = new ApiClient(API_URL);3 React Hooks 생성
src/hooks/useProjects.ts 파일을 만듭니다:
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { apiClient } from '../api/client';
// 타입 정의
interface Project {
id: string;
name: string;
description?: string;
created_at: string;
updated_at: string;
}
interface ProjectCreate {
name: string;
description?: string;
}
interface ProjectListResponse {
items: Project[];
total: number;
}
// Hooks
export function useProjects() {
return useQuery({
queryKey: ['projects'],
queryFn: () => apiClient.get<ProjectListResponse>('/api/v1/projects'),
});
}
export function useCreateProject() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: ProjectCreate) =>
apiClient.post<Project, ProjectCreate>('/api/v1/projects', data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['projects'] });
},
});
}
export function useDeleteProject() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => apiClient.delete(`/api/v1/projects/${id}`),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['projects'] });
},
});
}4 컴포넌트에서 사용하기
AI에게 기존 컴포넌트를 API 연결 버전으로 수정해달라고 요청합니다:
AI 프롬프트
작업 필요
"기존 App.tsx를 수정해서 API와 연결해줘. 변경사항: 1. 로컬 state 대신 useProjects, useCreateProject, useDeleteProject hooks 사용 2. 로딩 상태 표시 (isLoading) 3. 에러 상태 표시 (isError) 4. 생성/삭제 시 버튼 비활성화 (isPending) 기존 UI는 유지하고, 데이터 소스만 API로 변경해줘. 사용할 hooks: - useProjects() - { data, isLoading, isError } - useCreateProject() - { mutate, isPending } - useDeleteProject() - { mutate, isPending }"
기존 코드를 AI에게 보여 주면서 수정 요청하세요.
5 연결 확인
프론트엔드에서 프로젝트를 생성하면 백엔드 API에 저장됩니다.
프론트엔드에서 생성한 프로젝트가 백엔드 /docs의 GET API에서도 보이면 성공입니다!
CORS 에러가 발생한다면?
브라우저 콘솔에 "CORS" 에러가 보이면 백엔드의 CORS 설정을 확인하세요:
- 백엔드
main.py에서allow_origins확인 ["http://localhost:5173"]이 포함되어야 함- 백엔드 서버 재시작
자세한 해결 방법은 CORS 트러블슈팅을 참고하세요.