티스토리 뷰

 

웹 개발 생태계에서 Next.js는 이제 선택이 아닌 필수에 가까운 도구가 되었습니다. 특히 App Router의 등장은 기존 Pages Router의 한계를 넘어, 서버 중심의 렌더링 최적화와 직관적인 개발 경험을 제공하는 변곡점이 되었죠. 단순히 "파일을 만들면 페이지가 생긴다"는 개념을 넘어, 내부적으로 어떻게 효율적인 라우팅 아키텍처를 구축하는지 깊게 파헤쳐 보겠습니다.


1. 파일이 곧 주소가 되는 마법: 라우팅의 본질

과거의 웹 개발에서는 특정 URL로 접속했을 때 어떤 화면을 보여줄지 결정하기 위해 복잡한 설정 파일(예: React Router의 <Route> 설정)을 관리해야 했습니다. 프로젝트가 커질수록 이 설정 파일은 가독성을 잃고 관리하기 까다로워졌죠.

Next.js의 **파일 시스템 기반 라우팅(File-based Routing)**은 이 과정을 물리적인 폴더 구조로 대체합니다. 개발자가 폴더를 만드는 행위 자체가 곧 애플리케이션의 지도(Map)를 그리는 과정이 되는 셈입니다.

💡 쉬운 비유: 아파트 단지의 주소 체계

이해를 돕기 위해 아파트 단지를 예로 들어볼까요?

  • app 폴더: 아파트 단지 정문입니다.
  • 하위 폴더: '101동', '102동' 같은 건물입니다.
  • page.js: 그 건물에 들어갔을 때 실제로 거주자가 살고 있는 '호수(내부 공간)'입니다.
  • layout.js: 모든 동에 공통으로 적용되는 '보안 출입문'이나 '엘리베이터' 같은 공용 시설입니다.

아무리 폴더(동)를 많이 만들어도 그 안에 page.js(거주 공간)가 없다면, 우체부(브라우저)는 해당 주소로 편지를 배달할 수 없습니다.


2. 핵심 개념 Deep Dive: 구조와 예약어

App Router는 특정 이름을 가진 파일을 통해 라우팅의 동작을 정의합니다.

  • page.js: 해당 경로의 고유한 UI를 정의합니다. 이 파일이 있어야만 공용 경로로 접근이 가능합니다.
  • layout.js: 여러 페이지 간에 공유되는 UI입니다. 상태를 유지하며 리렌더링되지 않아 성능 최적화에 유리합니다.
  • loading.js: 데이터 로딩 중에 보여줄 스켈레톤 UI를 정의합니다. React Suspense를 기반으로 동작합니다.
  • error.js: 예상치 못한 에러가 발생했을 때 사용자에게 보여줄 폴백(Fallback) 화면입니다.

3. 실전 예제: 이커머스 카테고리 & 상품 상세 페이지

단순한 구조를 넘어, 실제 비즈니스 로직에서 가장 많이 쓰이는 **다이내믹 라우팅(Dynamic Routing)**과 중첩 레이아웃을 적용해 보겠습니다.

폴더 구조

Plaintext
 
app/
├── (shop)/
│   ├── layout.js          # 쇼핑몰 공통 레이아웃 (네비게이션 바)
│   ├── category/
│   │   └── [slug]/
│   │       └── page.js    # 카테고리별 상품 목록 (/category/electronics)
│   └── products/
│       └── [id]/
│           └── page.js    # 상품 상세 페이지 (/products/123)
└── layout.js              # 루트 레이아웃 (HTML, Body 태그)

코드 구현: 상품 상세 페이지 (app/(shop)/products/[id]/page.js)

JavaScript
 
// 서버 컴포넌트로 동작하여 DB에 직접 접근하거나 API를 호출할 수 있습니다.
export default async function ProductDetailPage({ params }) {
  // URL 파라미터에서 상품 ID를 가져옵니다. (예: /products/102 -> id: 102)
  const { id } = params;

  // 실제 환경에서는 외부 API나 DB에서 데이터를 가져오는 로직이 들어갑니다.
  const product = await fetchProduct(id);

  if (!product) {
    return <div>상품을 찾을 수 없습니다.</div>;
  }

  return (
    <main className="p-8">
      <div className="flex flex-col md:flex-row gap-10">
        {/* 상품 이미지 영역 */}
        <div className="flex-1 bg-gray-100 rounded-lg aspect-square" />
        
        {/* 상품 정보 상세 */}
        <div className="flex-1 space-y-4">
          <h1 className="text-3xl font-bold">{product.name}</h1>
          <p className="text-xl text-blue-600 font-semibold">
            {product.price.toLocaleString()}원
          </p>
          <hr />
          <p className="text-gray-600 leading-relaxed">
            {product.description}
          </p>
          <button className="w-full bg-black text-white py-4 rounded-md hover:bg-gray-800 transition">
            장바구니 담기
          </button>
        </div>
      </div>
    </main>
  );
}

// 가상의 데이터 페칭 함수
async function fetchProduct(id) {
  // 비동기 처리를 시뮬레이션합니다.
  return {
    id,
    name: `프리미엄 기계식 키보드 (모델 ID: ${id})`,
    price: 189000,
    description: "최고의 타건감을 제공하는 전문가용 키보드입니다. 저소음 적축이 적용되었습니다."
  };
}

🛠️ 트러블슈팅 팁

  1. 404 에러 발생: 폴더명에 오타가 없는데 주소를 못 찾는다면, 해당 폴더 안에 page.js가 있는지 확인하세요. 폴더만으로는 경로가 활성화되지 않습니다.
  2. 클라이언트 기능 오류: onClick이나 useState를 사용해야 한다면 파일 최상단에 'use client'; 지시어를 반드시 추가해야 합니다. App Router의 모든 파일은 기본적으로 서버 컴포넌트입니다.

4. 장단점 및 고려사항 (Trade-offs)

장점

  • 직관적인 구조: 폴더 구조만 봐도 전체 서비스의 흐름을 한눈에 파악할 수 있습니다.
  • 자동 코드 분할: 각 라우트별로 번들 파일이 분리되어, 사용자가 방문하지 않은 페이지의 코드는 불러오지 않습니다. 로딩 속도가 비약적으로 향상됩니다.
  • 레이아웃 효율성: 페이지 이동 시 변경되는 부분만 렌더링되므로 부드러운 사용자 경험을 제공합니다.

한계와 대안

  • 학습 곡선: 서버 컴포넌트와 클라이언트 컴포넌트의 경계를 이해하고 데이터를 어디서 호출할지 결정하는 데 시간이 필요합니다.
  • 복잡한 중첩: 폴더 깊이가 너무 깊어지면 오히려 파일 위치를 찾기 어려울 수 있습니다. 이때는 (Group folders)를 활용해 논리적으로 그룹화하는 전략이 필요합니다.

5. 결론 및 제언

Next.js App Router의 파일 시스템 라우팅은 단순한 편리함을 넘어, 웹 애플리케이션의 성능과 구조를 강제로 최적화해 주는 강력한 규약입니다. "설정보다 관습(Convention over Configuration)"을 따름으로써 개발자는 비즈니스 로직에 더 집중할 수 있게 되었습니다.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함