하위 태스크 1

병렬 라우트 구조 생성

@folder 패턴으로 슬롯 디렉토리 생성

mkdir parallel
mkdir parallel/@sidebar
mkdir paraller/@feed

하위 태스크 2

레이아웃에서 슬롯 사용

layout.tsx에서 슬롯 props 받기

app/parallel/layout.tsx:

import { ReactNode } from "react";
 
export default function ParallelLayout({ children, sidebar, feed } : {
  children: ReactNode;
  sidebar: ReactNode;
  feed: ReactNode;
}) {
  return (
    <div>
      <aside>{sidebar}</aside>
      <main>{feed}</main>
      {children}
    </div>
  );
}

하위 태스크 3

default.tsx 구현

슬롯이 없을 때 기본 컴포넌트 표시

app/parallel/@feed/default.tsx:

export default function DefaultFeed() {
  return <div>기본 피드</div>;
}

app/parallel/@sidebar/default.tsx:

export default function DefaultSidebar() {
  return <div>사이드 바</div>;
}

app/parallel/layout.tsx:

import { ReactNode } from "react";
 
import DefaultSidebar from "./@sidebar/default";
import DefaultFeed from "./@feed/default";
 
export default function ParallelLayout({ children, sidebar, feed } : {
  children: ReactNode;
  sidebar: ReactNode;
  feed: ReactNode;
}) {
  return (
    <div className="flex mx-auto w-200">
      <aside className="w-50 bg-slate-200">{sidebar ?? <DefaultSidebar />}</aside>
      <main className="w-100 bg-slate-100">{feed ?? <DefaultFeed />}</main>
      <div className="w-50 bg-slate-300">{children}</div>
    </div>
  );
}

app/parallel/page.tsx:

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

하위 태스크 4

조건부 렌더링

URL에 따라 다른 슬롯 표시

app/parallel/one/page.tsx:

export default function ParallelOne() {
  return <p>Parallel1</p>;
}

app/parallel/@feed/one/page.tsx:

export default function Sidebar() {
  return (
    <p>첫 번째 평행 세계로 어서오세요!</p>
 );
}

하위 태스크 5 ~ 6

가로채기 라우트 생성

(.) 패턴으로 라우트 가로채기

모달 컴포넌트 구현

모달 UI 컴포넌트 생성

app/@modal/(.)book/[id]/page.tsx:

import BookPage from "@/app/book/[id]/page";
import { ReactNode } from "react";
 
function Modal({ children }: { children: ReactNode }) {
  return (
    <div className="fixed flex h-screen w-screen items-center justify-center bg-slate-500 bg-opacity-50">
      <div className="p-4 w-80 mx-auto bg-slate-200">{children}</div>
    </div>
  );
}
 
export default function InterceptedPage() {
  return (
    <Modal>
      <BookPage />
    </Modal>
  );
}

app/@modal/default.tsx:

export default function DefaultModal() {
  return null;
}

app/book/[id]/page.tsx:

export default function BookPage() {
  return (
    <article>
      <ul className="pl-4 list-disc">
        <h2 className="font-bold">별</h2>
        <li>작가: 알퐁스 도데</li>
        <li>출판: 더클래식</li>
        <li>가격: 8,800원</li>
      </ul>
    </article>
  );
}

하위 태스크 7

모달 슬롯 추가

루트 레이아웃에 모달 슬롯 추가

app/layout.tsx:

import "./globals.css";
 
export default function RootLayout({
  children,
  modal,
}: Readonly<{
  children: React.ReactNode;
  modal: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className="min-h-full flex flex-col">
        {children}
        {modal}
      </body>
    </html>
  );
}

하위 태스크 8

병렬 로딩 구현

각 슬롯의 독립적인 로딩 상태

app/parallel/@sidebar/loading.tsx:

export default function SidebarLoading() {
  return <div>사이드 바 로딩...</div>;
}

app/parallel/@feed/loading.tsx:

export default function FeedLoading() {
  return <div>피드 로딩...</div>;
}

하위 태스크 9

Route Groups 활용

괄호로 그룹화하여 레이아웃 공유

@modal, book, parallel, layout.tsx, page.tsx를 Route Group을 활용해 레이아웃을 공유시킬 수 있다.

mv @modal (example)/@modal
mv book (example)/book
mv parallel (example)/parallel
mv layout.tsx (example)/layout.tsx
mv page.tsx (example)/page.tsx