빵 입니다.

Next.js에서의 라우팅 본문

프론트엔드/Next.js

Next.js에서의 라우팅

bread-gee 2024. 4. 18. 09:34

안뇽하세요~

넥스트 라우팅 관련하여 좋은 글들이 아주 많았는데

스스로 학습하고 머릿 속에 정리해 놓으려고 저만의 언어로 요약해 보았습니다~

최하단에 출처를 남겨놓았으니 원본 글들도 꼭 봐주세요~

 

---

[목차]

1. 라우팅

- 리액트 라우팅 vs 넥스트 라우팅

- 라우팅 컨벤션

 

2. Index routes

- Root Path

- 원하는 라우팅 생성

- Layout 패턴

 

3. Nested Routes (중첩된 라우트)

 

4. Dynamic Routes (다이나믹 라우트 / 동적 라우트 매칭)

- 동적 데이터에서 경로를 생성하려는 경우

- 정확한 세그먼트 이름을 모르는 경우

-- Catch-all Segments (모든 경우의 수를 캐치하기)

-- Optional Catch-all Segments (모든 경우의 수를 선택적으로 캐치하기)

- params

 

5. Nested Dynamic Routes (중첩된 다이나믹 라우트)

 

6. Custom Not Found Page (404)

---

 

1. 라우팅

🧿 리액트 라우팅 vs 넥스트 라우팅

기존의 React에서는 라우팅을 기본적으로 제공하지 않아 react-router-dom 패키지를 설치해 라우팅을 작업했다.

넥스트에서는 라우팅을 지원하기 때문에 라우터를 별도로 설치하지 않고 라우팅 작업을 할 수 있다.

넥스트는 파일시스템 기반의 라우팅을 지원하는데, app > pages 폴더 안에 page 컴포넌트를 생성하면 자동으로로 라우팅이 생성된다.

👉🏻 폴더와 파일로 라우팅 구성

 

🧿 라우팅 컨벤션

  • 모든 라우팅은 app 폴더 안에 존재한다.
  • 라우팅되는 파일명은 page.js(pages.tsx) 등 "page"로 선언한다.
  • 폴더명이 브라우저에서 보이는 URL path가 된다.

 

2. Index routes

넥스트는 파일시스템 기반의 라우팅을 지원하는데, app > pages 폴더 안에 page 컴포넌트를 생성하면 자동으로로 라우팅이 생성된다.

🧿 Root Path

단, 루트 페이지는 app 폴더 안에 직속으로 생성된다.

가장 기본적인 '/' 주소는 'src/app/page.tsx'와 매칭된다.

=> localhost:3000/

 

🧿 원하는 라우팅 생성

about 페이지 생성하려면?

app/about/page.tsx ==> '/about' 라우팅에 대응 => localhost:3000/about

── app
 ├─ about
 │   └─ page.tsx
 ├─ layout.tsx
 └─ page.tsx

 

boards 페이지 생성하려면?

app/boards/page.tsx ==> '/boards' 라우팅에 대응 => localhost:3000/boards

── app
 ├─ about
 │   └─ page.tsx
 ├─ boards
 │   └─ page.tsx
 ├─ layout.tsx
 └─ page.tsx

 

🧿 Layout 패턴

넥스트를 설치하면 app 폴더에 layout.tsx와 page.tsx가 추가되는데

layout 파일은 말그대로 공통적인 레이아웃을 설정할 수 있게 해주는 파일이다.

app 폴더의 직속 layout 파일은 RootLayout이라는 이름으로 선언되어 있고, html 가장 기본의 구조를 제공한다.

 

3. Nested Routes (중첩된 라우트)

중첩된다는 말은 단순히 '/about'이 아닌

'/about/family', '/about/school' 등 하위의 path가 추가되었단 뜻이다.

localhost:3000/about
localhost:3000/about/family
localhost:3000/about/school

 

about 폴더 하위에 family, school 각각의 폴더를 만들고, page.tsx를 생성하면 된다.

── app
 ├─ about
 │   ├─ family
 │   │  └─ page.tsx
 │   ├─ school
 │   │  └─ page.tsx
 │   └─ page.tsx
 ├─ boards
 │   └─ page.tsx
 ├─ layout.tsx
 └─ page.tsx

 

4. Dynamic Routes (다이나믹 라우트 / 동적 라우트 매칭)

동적 데이터에서 경로를 생성한다거나 정확한 세그먼트 이름을 모르는 경우 요청 시 동적으로 라우트가 채워지거나 빌드 시 미리 렌더링되는 동적 세그먼트를 사용할 수 있다.

 

🧿 동적 데이터에서 경로를 생성하려는 경우

주어진 패턴을 가진 라우트를 동일한 컴포넌트에 매핑해야하는 경우가 자주 있는데, 그럴 경우 다이나믹 라우팅을 사용하면 된다.

모든 글이 동일한 레이아웃(공통 컴포넌트)을 가지고, id 값에 따라 내용이 바뀌는 게시판이 있다면?

 

localhost:3000/boards
localhost:3000/boards/1
(localhost:3000/boards/boardId)

 

boards의 하위 path로 boardId 값을 가지고, boardId가 어떤 값이든 처리해 줄 수 있는 구조를 만들어야 한다.

그럴 경우 다이나믹 라우팅(대괄호 사용)을 사용해 공통으로 사용하는 path를 생성하면 된다.

공통으로 사용하는 [boardId] 폴더를 생성하고, 공통 레이아웃으로 사용될 공통 컴포넌트인 page.tsx를 추가한다.

── app
 ├─ about
 │   ├─ family
 │   │  └─ page.tsx
 │   ├─ school
 │   │  └─ page.tsx
 │   └─ page.tsx
 ├─ boards
 │   ├─ [boardId]
 │   │  └─ page.tsx
 │   └─ page.tsx
 ├─ layout.tsx
 └─ page.tsx

 

저의 경우 app > boards > page.tsx는 게시판 목록으로 사용하고, app > boards > [boardId] > page.tsx는 게시판 상세로 사용합니다.

 

🧿 정확한 세그먼트 이름을 모르는 경우

👉🏻 Catch-all Segments (모든 경우의 수를 캐치하기)

사이트의 규모가 커질수록 여러 라우트가 생길텐데, 모든걸 동적 라우트만으로 처리할 수 없다.

그럴 땐, 좀 더 유연하게~ 하나의 라우트로 후속 세그먼트들을 모두 대응할 수 있다.

 

[...segementName]

대괄호 안에 줄임표를 추가하면 동적 세그먼트를 모든 후속 세그먼트(/path)로 확장할 수 있다.

 

예를 들어, pages/shop/[...slug]/page.tsx는

/shop/clothes와 일치하지만, /shop/clothes/tops, /shop/clothes/tops/t-shirts 등과도 일치한다.

Route Example URL params
pages/shop/[...slug]/page.tsx /shop/a { slug: ['a'] }
pages/shop/[...slug]/page.tsx /shop/a/b { slug: ['a', 'b'] }
pages/shop/[...slug]/page.tsx /shop/a/b/c { slug: ['a', 'b', 'c'] }

 

👉🏻 Optional Catch-all Segments (모든 경우의 수를 선택적으로 캐치하기)

slug를 사용하여 pages/shop/[...slug]/page.tsx를 생성했는데, 매개변수가 없는 경로로 접근한다면?

(위의 주소에서 /shop으로 접근한다면?)

[[...segementName]]

이중 대괄호를 사용해 매개변수를 포함하여 포괄적인 세그먼트를 선택적으로 만들 수 있다.

(slug 값이 없어도 동작할 수 있다.)

 

예를 들어, Pages/shop/[[...slug]]/page.tsx는

/shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts 외에도 /shop과도 일치한다.

Route Example URL params
pages/shop/[[...slug]]/page.tsx /shop { slug: undefined }
pages/shop/[[...slug]]/page.tsx /shop/a { slug: ['a'] }
pages/shop/[[...slug]]/page.tsx /shop/a/b { slug: ['a', 'b'] }
pages/shop/[[...slug]]/page.tsx /shop/a/b/c { slug: ['a', 'b', 'c'] }

 

📌 /shop에 직속으로 page.tsx를 생성하면 되는거 아닌가?라는 생각을 할수도 있는데

더보기

그럴 경우...

You cannot define a route with the same specificity as a optional catch-all route ("/shop" and "/shop[[...slug]]").

에러 메시지를 볼 수 있다.

 

/shop은 /shop/path, /shop/path/path 등등을 대응해야 하는데, /shop에 직속으로 page.tsx를 추가하면 slug가 제대로 동작하지 않기 때문에, /shop에 대응하는 명시적인 라우트를 정의할 수 없다는 의미이다.

 

🧿 params

폴더명에 대괄호를 사용하면 넥스트가 동적인 라우트임은 인지하고, 대괄호 안의 내용 파라미터로 만든다.

params는 /path 값이고, searchParams는 path에 붙어있는 쿼리스트링 값이다.

// app > boards > [boardId] > page.tsx
export default function BoardDetails(props: any) {
    console.log(props);
    return (
        <h1>
        	Board {props.params.boardId} / {props.searchParams.filter} Details
        </h1>
    );
}

 

localhost:3000/boards/1로 이동하면,

props는 { params: { boardId: '1' }, searchParams: {} } 객체를 받아온다.

 

localhost:3000/boards/1?filters=today로 이동하면,

props는 { params: { boardId: '1' }, searchParams: { filters: 'today' } } 객체를 받아온다.

URL 쿼리 문자열은 물음표(?) 표시 뒤로 Key-Value 값 형태로 나타낼 수 있다.

 

📌 params의 값은 항상 string이다. 숫자 1을 넘겨도 string으로 받아온다.

 

5. Nested Dynamic Routes (중첩된 다이나믹 라우트)

[]를 사용해 공통 컴포넌트를 사용을 지원하는 다이나믹 라우트가 중첩되어 있다면?

 

localhost:3000/boards/1
localhost:3000/boards/1/filters/today
(localhost:3000/boards/[boardId]/filters/[filterName])
── app
 ├─ about
 │   ├─ family
 │   │  └─ page.tsx
 │   ├─ school
 │   │  └─ page.tsx
 │   └─ page.tsx
 ├─ boards
 │   ├─ [boardId]
 │   ├── filters
 │   │   ├─ [filterName]
 │   │   └─ page.tsx
 │   └─ page.tsx
 ├─ layout.tsx
 └─ page.tsx

 

구현 방법은 다이나믹 라우트와 같다.

폴더가 더 중첩되어 있느냐 아니냐의 차이이다.

 

📌  최하위 자식 컴포넌트에서 부모 컴포넌트의 params에 모두 접근이 가능하단 점이다.

 

// app > boards > [boardId] > filters > [filterName] > page.tsx
export default function filterDetails({
    		params,
        }: {
            params: {
            boardId: string;
            filterName: string;
        };
    }) {
    console.log(params);
    return (
        <>
            <h1>Board Id : {params.boardId}</h1>
            <h1>Filter Name : {params.filterName}</h1>
        </>
    );
}

 

6. Custom Not Found Page (404)

라우팅 제공해주지 않는 페이지에 접근하면 404 에러 페이지가 뜬다.

우린 이걸 커스텀해서 사용할 수 있다!

 

app에 직속으로 추가해야 하고, 파일명은 반드시 not-found 이어야 한다.

── app
 ├─ about
 │   ├─ family
 │   │  └─ page.tsx
 │   ├─ school
 │   │  └─ page.tsx
 │   └─ page.tsx
 ├─ boards
 │   ├─ [boardId]
 │   ├── filters
 │   │   ├─ [filterName]
 │   │   └─ page.tsx
 │   └─ page.tsx
 ├─ layout.tsx
 ├─ not-found.tsx
 └─ page.tsx

 


👍출처👍

https://nextjs.org/docs/pages/building-your-application/routing/pages-and-layouts

https://mycodings.fly.dev/blog/2024-01-13-nextjs-14-tutorial-1-all-about-routing

https://velog.io/@hamjw0122/Next.js-Next.js%EC%9D%98-Route-System

https://velog.io/@sean2337/Next.js-Next.js-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90%EC%84%9C%EC%9D%98-%EA%B7%9C%EC%B9%99%EA%B3%BC-%EB%9D%BC%EC%9A%B0%ED%8C%85

 

'프론트엔드 > Next.js' 카테고리의 다른 글

라이브러리와 프레임워크 / React와 Next  (0) 2023.11.29
Comments