React 실무 가이드 · Part 10

라우팅과 프로젝트 구조

화면이 늘어나도 흐트러지지 않는 구조 만들기

작성 기준2026년 7월버전과 지원 현황은 이후 달라질 수 있으니 공식 문서를 함께 확인하세요.

이 파트에서 다루는 내용

라우팅 기본URL 설계코드 스플리팅폴더 구조와 설정
01

React에는 라우팅이 없습니다

React 자체는 URL을 다루지 않습니다. 여러 화면을 오가려면 라우팅 라이브러리를 별도로 붙여야 합니다. Part 1에서 말한 조합의 대표적인 예입니다.

라우팅이 하는 일은 단순합니다. 현재 URL을 보고 어떤 컴포넌트를 보여 줄지 정하고, 페이지 새로고침 없이 화면을 전환합니다.

중첩 라우팅
레이아웃 공유

공통 레이아웃 안에 화면이 바뀌는 영역을 두는 구성입니다. 헤더와 사이드바를 유지한 채 본문만 전환합니다.

경로 파라미터
동적 경로

상세 화면처럼 식별자가 들어가는 경로를 다룹니다. 해당 값은 컴포넌트에서 읽어 데이터를 조회하는 데 씁니다.

보호된 경로
인증

로그인이 필요한 화면은 진입 시점에 검사해 로그인 화면으로 보냅니다. 다만 화면 접근 제어는 보안 장치가 아니며 서버 권한 검사가 반드시 필요합니다.

404 처리
누락 주의

일치하는 경로가 없을 때 보여 줄 화면을 준비합니다. 빈 화면이 나오는 상태로 배포되는 경우가 흔합니다.

02

URL은 화면의 상태를 담습니다

Part 8에서 언급한 대로 URL도 상태 저장소입니다. 검색 조건이나 페이지 번호를 URL에 두면 얻는 것이 많습니다.

URL에 두면 좋은 것
기준
  • 검색어와 필터 조건
  • 페이지 번호와 정렬 기준
  • 선택된 탭
  • 상세 항목 식별자
얻는 것
효과
  • 새로고침해도 상태가 유지됩니다
  • 링크를 공유하면 같은 화면이 열립니다
  • 뒤로 가기가 자연스럽게 동작합니다
  • 즐겨찾기가 의미를 갖습니다
URL에 두지 말 것
주의
  • 개인정보와 토큰
  • 임시 입력 중인 폼 값
  • 화면 열림·닫힘 같은 순간적 상태
03

코드 스플리팅으로 초기 로딩을 줄입니다

화면이 늘어나면 번들 하나가 커지고, 처음 접속할 때 모든 화면의 코드를 내려받게 됩니다. 사용자는 첫 화면만 보는데도 말입니다.

라우트 단위로 코드를 나누면 필요한 시점에 내려받습니다. 가장 효과가 크고 적용도 쉬운 최적화입니다.

라우트 단위 분리jsx
import { lazy, Suspense } from "react";

const OrderListPage = lazy(() => import("./pages/OrderListPage"));
const StatisticsPage = lazy(() => import("./pages/StatisticsPage"));

function App() {
  return (
    <Suspense fallback={<PageSkeleton />}>
      <Routes>
        <Route path="/orders" element={<OrderListPage />} />
        <Route path="/statistics" element={<StatisticsPage />} />
      </Routes>
    </Suspense>
  );
}

차트나 편집기처럼 무거운 라이브러리를 쓰는 화면부터 분리하면 효과가 큽니다. fallback을 빈 화면으로 두면 전환할 때마다 깜빡이므로 레이아웃을 유지하는 형태로 만듭니다.

04

폴더 구조는 기능 단위가 오래갑니다

타입별로 나누는 방식(components, hooks, utils)은 처음에는 깔끔하지만, 기능 하나를 수정할 때 여러 폴더를 오가게 됩니다.

기능 단위로 묶으면 관련 파일이 한곳에 모입니다. 나중에 기능을 통째로 제거하거나 분리하기도 쉽습니다.

공용으로 올리는 기준
판단

두 개 이상의 기능에서 실제로 쓰이기 시작할 때 옮깁니다. 언젠가 쓸 것 같다는 이유로 미리 올리지 않습니다.

기능 간 직접 참조
주의

한 기능이 다른 기능 내부를 직접 가져다 쓰면 분리한 의미가 없어집니다. 필요하면 공용으로 올리거나 명시적인 통로를 둡니다.

기능 단위 구조text
src/
├─ features/
│  ├─ order/
│  │  ├─ components/     주문 화면 전용 컴포넌트
│  │  ├─ hooks/          주문 관련 훅
│  │  ├─ api/            주문 API 호출
│  │  └─ types.ts
│  └─ member/
├─ shared/               여러 기능이 함께 쓰는 것
│  ├─ components/        버튼, 모달 등 공용 UI
│  ├─ hooks/
│  └─ lib/
├─ pages/                라우트에 연결되는 화면
└─ app/                  전역 설정, 라우터, 프로바이더

처음부터 완벽한 구조를 만들 필요는 없습니다. 기능이 늘면서 자연스럽게 나누되, 공용으로 올릴 기준만 팀이 합의해 두면 됩니다.

05

환경별 설정과 배포 주의점

API 주소처럼 환경마다 달라지는 값은 환경변수로 분리합니다. 다만 프런트엔드 환경변수에는 중요한 제약이 있습니다.

빌드에 그대로 포함됩니다
가장 중요

프런트엔드 환경변수는 빌드 결과물에 문자열로 들어갑니다. 브라우저에서 확인할 수 있으므로 비밀키를 넣으면 그대로 노출됩니다.

넣어도 되는 것
구분

API 기본 주소, 기능 플래그, 공개용 식별자처럼 노출돼도 문제없는 값만 넣습니다.

절대 넣지 말 것
구분

서버 API 키, 데이터베이스 정보, 결제 비밀키. 이런 값은 서버를 거쳐 사용해야 합니다.

SPA 배포 설정
자주 겪는 문제

직접 URL로 접속하면 404가 나는 경우가 있습니다. 모든 경로를 index.html로 연결하도록 서버나 호스팅 설정이 필요합니다.

버전

버전별 참고

본문은 React 19 기준입니다. 18과 달라지는 부분은 아래에 정리합니다.

  • 라우팅 라이브러리는 React 버전과 별개로 자체 메이저 버전 변화가 큽니다. 예제를 참고할 때 어느 버전 기준인지 먼저 확인합니다.
  • React 19의 문서 메타데이터 지원으로 화면별 제목과 설명을 컴포넌트 안에서 직접 선언할 수 있습니다. 18 이하에서는 별도 라이브러리를 씁니다.
  • 코드 스플리팅과 Suspense는 18 이상에서 동일하게 동작합니다.
체크

이 파트 완료 기준