🐨CoalaCoding
DocsExamplesTry itBoardB반B반
🐨CoalaCoding

개발자를 위한 한국어 웹 기술 문서

문서

  • JavaScript
  • Web Publishing
  • React
  • Python

커뮤니티

  • 게시판
  • 예제 모음
  • Try it 에디터

기타

  • GitHub
  • 관리자
© 2026 CoalaCoding. All rights reserved.
  • GOFLIX 프로젝트 소개와 개발환경 설정
  • React 진입점과 라우팅 설정
  • Axios로 TMDB API 연결하기
  • 공통 UI 컴포넌트 만들기 (UI.jsx)
  • App.jsx — 레이아웃 구성과 데이터 가져오기
  • Header와 Footer 만들기
  • Home.jsx — 메인 페이지 완성하기
  • Section과 Card — 영화 카드 목록 만들기
  • MovieDetail — 영화 상세 페이지 만들기
  • Category, ErrorPage 완성하기
  • AI 챗봇 연동하기
  • Swiper_캐러셀_적용과_프로젝트_마무리
  • GOFLEX Gemini CLI 바이브코딩 프롬프트 템플릿
  • 무비앱-완료본
  1. 홈
  2. 문서
  3. React
  4. 프로젝트: 영화앱
  5. React 진입점과 라우팅 설정

React 진입점과 라우팅 설정

main.jsx에서 앱을 시작하고 React Router로 페이지를 나누는 방법

코드 블록의 Try it Yourself 버튼으로 직접 실행할 수 있다.

구문

Tip: Gemini CLI로 구현하기 — 진입점 & 라우팅 설정

  • 프롬프트: gemini "React 19 + Vite 프로젝트에서 main.jsx와 App.jsx를 작성해줘. main.jsx에는 BrowserRouter로 앱을 감싸고, App.jsx에는 Routes를 구성해줘. 페이지 컴포넌트는 Home, MovieDetail, Category, ErrorPage이고, 경로는 각각 /, /movie/:id, /category/:type, * 야. [파일 경로: src/]"
    • 사용 가이드: [파일 경로]를 실제 src 폴더 경로로 바꾼다. 생성된 파일을 src/ 폴더에 저장한다.

1. React 앱은 어디서 시작될까?

브라우저가 웹사이트를 열면, 가장 먼저 index.html 파일을 읽는다. 이 파일 안에 React가 연결되는 출발점이 있다.

<!doctype html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>frontend</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>
줄설명
10핵심! React가 이 div 안에 모든 화면을 그린다. id="root"가 React의 시작점이다.
11main.jsx 파일을 불러온다. 이 파일이 React 앱을 실제로 실행시킨다.

Info: React는 빈 div 하나에 JavaScript로 화면을 그리는 방식이다. 이것을 SPA(Single Page Application, 싱글 페이지 애플리케이션)라고 부른다.


2. main.jsx 작성 — React의 출발점

src/main.jsx 파일을 열고 아래 코드를 작성한다.

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";

import App from "./App.jsx";
import { Home } from "./components/Home.jsx";
import { MovieDetail } from "./components/MovieDetail.jsx";
import { ErrorPage } from "./components/ErrorPage.jsx";
import { Category } from "./components/Category.jsx";

import { createBrowserRouter, RouterProvider } from "react-router";

const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
    errorElement: <ErrorPage />,
    children: [
      { index: true, element: <Home /> },
      { path: "movie/:id", element: <MovieDetail /> },
      { path: "category/:type", element: <Category /> },
    ],
  },
]);

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

코드가 세 부분으로 나뉜다. 탭을 눌러 각 역할을 확인해 보자.

① import 영역

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";

import App from "./App.jsx";
import { Home } from "./components/Home.jsx";
import { MovieDetail } from "./components/MovieDetail.jsx";
import { ErrorPage } from "./components/ErrorPage.jsx";
import { Category } from "./components/Category.jsx";

import { createBrowserRouter, RouterProvider } from "react-router";
줄설명
1StrictMode(스트릭트모드) — 개발 중 잠재 문제를 경고한다.
2createRoot — React 앱을 DOM에 연결하는 함수이다.
3Tailwind CSS + 폰트 설정 파일을 불러온다.
5전체 레이아웃 역할의 App 컴포넌트이다.
6-10각 페이지 컴포넌트를 가져온다. 아직 만들지 않았으므로 나중에 하나씩 만든다.
11URL 경로와 컴포넌트를 연결하는 라우팅 도구이다.

② 라우터 설정

const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
    errorElement: <ErrorPage />,
    children: [
      { index: true, element: <Home /> },
      { path: "movie/:id", element: <MovieDetail /> },
      { path: "category/:type", element: <Category /> },
    ],
  },
]);
줄설명
3path: "/"는 메인 페이지(홈)의 경로이다.
4메인 경로에서 App 컴포넌트를 렌더링한다.
5존재하지 않는 URL에 접속하면 ErrorPage를 보여준다.
7index: true — "/"에 접속하면 기본으로 Home을 표시한다.
8movie/:id — :id는 동적 파라미터. movie/550처럼 숫자가 바뀐다.
9category/:type — :type은 popular, now_playing, top_rated 등이 온다.

③ 렌더링

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <RouterProvider router={router} />
  </StrictMode>,
);
줄설명
1index.html의 div#root를 찾아 React 앱을 연결한다.
2-4StrictMode로 앱 전체를 감싸고, RouterProvider에 라우터를 전달한다.

3. 라우팅의 동작 원리

URL표시되는 컴포넌트
http://localhost:5173/App 안에 Home 표시
http://localhost:5173/movie/550App 안에 MovieDetail 표시
http://localhost:5173/search?q=어벤져스App 안에 Search 표시
http://localhost:5173/category/popularApp 안에 Category 표시
존재하지 않는 URLErrorPage 표시

App 컴포넌트는 항상 화면에 있고(헤더+푸터), URL이 바뀌면 App 안쪽 내용만 교체된다. 이 구조를 중첩 라우팅(Nested Routing, 네스티드 라우팅)이라 한다.

Tip: 넷플릭스를 떠올려 보자. 상단의 로고와 메뉴는 항상 그대로인데, 메인 콘텐츠 영역만 바뀐다. 이것이 바로 중첩 라우팅이다.


4. 동적 라우트 파라미터 이해하기

이 프로젝트에는 두 종류의 동적 파라미터가 있다.

경로파라미터예시 URL값
movie/:id:id/movie/550"550"
category/:type:type/category/popular"popular"

나중에 각 컴포넌트에서 useParams() 훅으로 이 값을 꺼내 API에 요청을 보낸다.


5. errorElement란?

errorElement: <ErrorPage />,

사용자가 존재하지 않는 URL(예: /abcdef)에 접속하면 React Router가 자동으로 ErrorPage 컴포넌트를 보여준다.


6. 아직 없는 컴포넌트 임시 생성

지금 main.jsx가 여러 컴포넌트를 import 하고 있지만, 아직 해당 파일들이 존재하지 않는다. 이 상태로 개발 서버를 실행하면 에러가 발생한다. src/components/ 폴더 안에 아래 4개 파일을 각각 생성하고, 코드를 한 줄씩 입력한다.

Home

export function Home() {
  return <div>Home 페이지 (준비중)</div>;
}

MovieDetail

export function MovieDetail() {
  return <div>MovieDetail 페이지 (준비중)</div>;
}

ErrorPage

export function ErrorPage() {
  return <div>404 에러 페이지 (준비중)</div>;
}

Category

export function Category() {
  return <div>Category 페이지 (준비중)</div>;
}
export default vs export function 차이

이 프로젝트에서는 App.jsx만 export default를 사용하고, 나머지 컴포넌트는 export function(named export)을 사용한다.

방식코드가져올 때
export defaultexport default function App()import App from "./App"
named exportexport function Home()import { Home } from "./Home"

중괄호 { } 유무에 주의한다.


7. App.jsx 임시 생성

src/App.jsx 파일을 열고 기존 내용을 모두 지운 뒤, 아래 코드로 교체한다. Outlet(아울렛)은 URL이 바뀔 때 하위 페이지가 표시되는 빈자리라고 생각하면 된다. 액자의 틀은 그대로인데 안에 들어가는 사진만 바뀌는 것과 같다.

import { Outlet } from "react-router";

export default function App() {
  return (
    <div>
      <h1>GOFLEX</h1>
      <Outlet />
    </div>
  );
}

8. 동작 확인

npm run dev
확인 항목기대 결과
http://localhost:5173/"GOFLEX"와 "Home 페이지 (준비중)" 텍스트 표시
http://localhost:5173/movie/550"GOFLEX"와 "MovieDetail 페이지 (준비중)" 텍스트 표시
http://localhost:5173/abcdef"404 에러 페이지 (준비중)" 텍스트 표시

9. 전체 코드

src/main.jsx

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";

import App from "./App.jsx";
import { Home } from "./components/Home.jsx";
import { MovieDetail } from "./components/MovieDetail.jsx";
import { ErrorPage } from "./components/ErrorPage.jsx";
import { Category } from "./components/Category.jsx";

import { createBrowserRouter, RouterProvider } from "react-router";

const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
    errorElement: <ErrorPage />,
    children: [
      { index: true, element: <Home /> },
      { path: "movie/:id", element: <MovieDetail /> },
      { path: "category/:type", element: <Category /> },
    ],
  },
]);

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

src/App.jsx (임시)

import { Outlet } from "react-router";

export default function App() {
  return (
    <div>
      <h1>GOFLEX</h1>
      <Outlet />
    </div>
  );
}

목차

  • 구문