Vite + React 프로젝트에 라우팅/서버상태/스타일링 기본 뼈대 세팅하기 (React Router + TanStack Query + Tailwind v4)

Alchemist·2026년 3월 3일

작업 배경

실제 서비스 형태로 확장하기 위해서 이번 작업에서는 앱 개발에 필요한 핵심 인프라(라우팅/데이터/스타일)를 먼저 붙여서 “뼈대”를 만들었다.

  • 라우팅: 페이지 단위 구조(리스트/상세/설정 등)로 확장 가능해야 함
  • 서버 상태 관리: API 요청/캐싱/로딩/재요청 정책을 표준화하고 싶음
  • 스타일링: 템플릿 기본 CSS 대신 Tailwind 기반으로 빠르게 UI를 잡고 싶음

이번 작업 목표

  • React Router로 기본 라우팅 구조 구성
  • TanStack React Query로 API 호출 표준(캐싱/리패치 정책) 구성
  • Tailwind CSS v4로 전역 스타일 엔트리 정리
  • Vite 템플릿 보일러플레이트(기본 로고/기본 CSS) 제거
  • LiveReserveList 페이지용 플레이스홀더 화면 추가

변경 사항 한눈에 보기

구분내가 한 일
의존성 추가react-router, @tanstack/react-query, tailwindcss, @tailwindcss/vite
Tailwind 적용vite.config.ts에 Tailwind 플러그인 추가 + src/index.css를 Tailwind 엔트리로 변경
React Query 적용QueryClient 분리(src/libs/queryClient.ts) + 루트에 QueryClientProvider 연결
Router 적용src/routes.tsx 생성 + 루트에 RouterProvider 연결
템플릿 제거src/App.css, src/assets/react.svg 삭제
페이지 추가src/liveReserveList.tsx 플레이스홀더 추가

1) Tailwind CSS v4 적용

1-1. Vite 설정에 Tailwind 플러그인 추가

vite.config.ts@tailwindcss/vite 플러그인을 추가했다.

    import { defineConfig } from "vite";
    import react from "@vitejs/plugin-react";
    import tailwindcss from "@tailwindcss/vite";

    export default defineConfig({
        plugins: [
            react({
                babel: {
                    plugins: [["babel-plugin-react-compiler"]],
                },
            }),
            tailwindcss(),
        ],
    });

1-2. 전역 CSS를 Tailwind 엔트리로 정리

기존 Vite 템플릿 기본 CSS를 제거하고 src/index.css를 아래처럼 단순화했다.

    @import "tailwindcss";

이제부터 컴포넌트에서 className="bg-red-50" 같은 Tailwind 유틸 클래스를 바로 쓸 수 있다.


2) TanStack React Query 세팅

2-1. QueryClient를 파일로 분리

src/libs/queryClient.ts를 만들고 QueryClient 인스턴스를 분리했다.

    import { QueryClient } from "@tanstack/react-query";

    const queryClient = new QueryClient();

    export default queryClient;

2-2. 앱 루트에 Provider 연결

src/main.tsx에서 앱 전체를 QueryClientProvider로 감쌌다.

    import { StrictMode } from "react";
    import { createRoot } from "react-dom/client";
    import "./index.css";
    import { RouterProvider } from "react-router";
    import { QueryClientProvider } from "@tanstack/react-query";

    import router from "./routes";
    import queryClient from "./libs/queryClient";

    createRoot(document.getElementById("root")!).render(
        <StrictMode>
            <QueryClientProvider client={queryClient}>
                <RouterProvider router={router} />
            </QueryClientProvider>
        </StrictMode>,
    );

이렇게 해두면 이후 어떤 페이지/컴포넌트에서도 useQuery, useMutation을 바로 사용할 수 있다.


3) React Router 기본 라우팅 구성

src/routes.tsx를 새로 만들고, createBrowserRouter로 라우트를 정의했다.

    import { createBrowserRouter } from "react-router";
    import App from "./App";
    import LiveReserveList from "./liveReserveList";

    const router = createBrowserRouter([
        {
            path: "/",
            element: <App />,
        },        
        {
            path: "liveReserveList",
            element: <LiveReserveList />,
        },
    ]);

    export default router;

현재는 최소 단위로 아래 3개만 잡아두고, 앞으로 페이지가 늘어날 수 있게 구조를 열어뒀다.

  • / → App
  • /liveReserveList → LiveReserveList

4) LiveReserveList 플레이스홀더 추가

라우팅만 먼저 연결해두고, 화면 개발은 다음 단계에서 진행하기 위해 간단한 플레이스홀더를 만들었다.

    export default function LiveReserveList() {
        return <div>LiveReserveList</div>;
    }

5) 템플릿 보일러플레이트 제거 + App 화면 정리

템플릿에 기본으로 들어있던 아래 파일을 제거했다.

  • src/App.css
  • src/assets/react.svg

그리고 App.tsx는 “템플릿 데모 화면” 대신 아래 두 가지를 확인하는 용도로 바꿨다.

  • NavLink로 라우팅 동작 확인
  • useQuery로 API 호출 방식/옵션 테스트
    import { useQuery } from "@tanstack/react-query";
    import { NavLink, useNavigation } from "react-router";

    function App() {
        const navigation = useNavigation();

        useQuery({
            queryKey: ["hi"],
            queryFn: async () => {
                const response = await fetch(
                    "https://www.mallprolive.co.kr/api/1.0/minishop/info",
                    {
                        method: "post",
                        headers: {
                            "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
                        },
                        body: "dealerID=test01",
                    },
                );

                const jsonData = await response.json();
                console.log(jsonData);
            },
            staleTime: 60_000,
            refetchOnMount: false,
            refetchOnWindowFocus: false,
            refetchOnReconnect: false,
        });

        return (
            <>
                <div className="bg-red-50">테스트1</div>
                <NavLink to="about">테스트2</NavLink>
            </>
        );
    }

    export default App;

마무리

이번 작업으로 “페이지 구조(라우팅) + 서버 상태 관리(React Query) + 스타일링(Tailwind)”의 기본 세팅을 끝냈다.
이제부터는 LiveReserveList 같은 실제 페이지 개발을 빠르게 진행할 수 있는 상태가 됐다.

profile
html_programming_language

0개의 댓글