Next.js Dynamic Route란? 

 

App router는 파일 구조로 router를 표현한다. 디렉토리는 path를, page.tsx는 UI를 나타낸다.

즉, 개발할 때 디렉토리명으로 path를 표현해야 한다.

그리고 Next.js는 Static 렌더링이 기본값이다. 이 말인즉슨 빌드 타임에 페이지가 렌더링된다는 뜻이다. 

그런데 path의 일부분이 변동되는 값이라 어떤 값이 들어올 지 정해지지 않았을 때는 path로 미리 url을 표현할 수 없을 것이다.

예를 들어, 유저 정보 페이지의 URL에 유저 id가 포함되어 있다고 한다면, 모든 유저의 id를 미리 정의해서 디렉토리로 생성해놓는 것은 불가능할 것이다. 

이럴 때 Dynamic Route를 사용할 수 있다. 즉 path에 어떤 값이 들어올 지 미리 알 수 없을 때 사용한다.

Dynamic Route 방식은 필요에 따라 3가지로 나눌 수 있다.

 

1. 일반적인 경우-디렉터리명을 대괄호로 감싼다. ex) [slug]

- app/user/[slug]/page.tsx -> /user/nightlybow23

2. 변동되는 path가 여러 개인 경우-디렉터리명을 두 개의 대괄호로 감싼다. ex) [[slug]]

- app/user/[[slug]]/page.tsx -> /user/nightlybow23/2024/may/25

3. 옵셔널하게 해당 path가 포함돼도 되고, 안 돼도 좋을 때-디렉터리명을 두 개의 대괄호로 감싸고, destructing할 때처럼 ...를 붙인다. ex) [[...slug]]

- app/user/[[...slug]]/page.tsx -> /user/nightlybow23, /user/nightlybow23/2013

 

* generateStaticParams은 Static 렌더링 + Dynamic Route 방식을 같이 사용하기 위한 함수이다. 

page.tsx에 컴포넌트 바깥에 export async function generateStaticParams로 시작하는 함수를 작성해야 한다.

아래와 같이 미리 작성해 놓으면 빌드 타임에 서버에서 미리 fetch를 수행한 후 route를 생성해 놓는다.

export async function generateStaticParams() {
    const users = await fetch(SOME_ENDPOINT)
    return users.map(user => ({
    	slug: user.id
    }))
}

 

generateStaticParams은 동일한 API 요청은 memoized되어 딱 한 번만 요청된다는 장점이 있다.

여러 페이지의 generateStaticParams끼리는 물론이고 page 컴포넌트 내에서도 동일한 API 요청을 한다면 중복 요청하지 않는다.

 

위 같은 장점들이 아니더라도 경험상, Dynamic API를 사용하지 않아 기본값인 Static 렌더링이 적용되고 있을 때, Dynamic Route 방식을 사용하려 하면 ([slug]) page.tsx에 generateStaticParams가 없다는 에러가 발생하며 페이지가 제대로 보여지지 않았다.

Static Rendering인 경우에는 반드시 generateStaticParams을 구현해야 함을 잊지 말자. 

 

'프론트엔드 > Nextjs' 카테고리의 다른 글

서버 렌더링  (0) 2025.01.07
Parallel Route  (0) 2025.01.07
1. 프로젝트 생성과 디렉토리 구조  (0) 2023.12.25

Next.js 공식 사이트에서 말하는 서버 렌더링의 장점은 아래와 같다.

 

1. 데이터 페칭 속도: 서버에서 데이터를 요청하기 때문에 클라이언트에서 해야 하는 요청이 줄어들어 시간이 절약된다.

2. 보안: 토큰이나 API 키 같은 정보를 클라이언트에 노출시키지 않고 사용할 수 있다.

3. 캐싱: 서버에서 렌더링된 결과를 캐싱하기 때문에, 유저에게서 요청이 올 때마다 매번 렌더링하지 않아도 된다.

4. 성능: 필요한 자바스크립트 코드의 양을 줄여서 클라이언트 경험에 도움이 된다. 특히 느린 인터넷, 오래된 기기 등에서 효과적이다.

5. 초기 페이지 로딩 및 FCP: 서버에서 미리 렌더링해서 보내주기 때문에 클라이언트가 자바스크립트를 다운로드하고, 파싱하고, 실행할 때까지 기다릴 필요가 없기 때문에 초기 페이지 로딩 및 FCP가 빠르다.

6. SEO: HTML이 미리 만들어져 있기 때문에 검색 엔진 봇이 인덱싱해가기 쉽다.

7. Streaming: Streaming을 사용하면 완성된 전체 페이지를 보여주는 대신, 렌더링 작업을 여러 개로 나눠서 준비되는 것부터 보여줄 수 있다.

 

Next.js의 컴포넌트는 기본적으로 모두 서버 컴포넌트이다. Next.js에서의 서버 컴포넌트 렌더링은 React와 다르지 않은데, 대략 아래와 같은 과정으로 이루어진다.

서버 측:

1. 서버 컴포넌트를 RSC Payload(React Server Component Payload)라는 특별한 형태로 변환한다.

2. 초기 페이지 HTML을 렌더링하기 위해서 서버 컴포넌트의 RSC Payload와 클라이언트 컴포넌트 자바스크립트를 사용한다.

클라이언트 측:

1. 상호작용 불가능한 HTML을 먼저 보여줘서 초기 페이지 로딩을 빠르게 한다.

2. RSC Payload를 사용해서 서버 컴포넌트와 클라이언트 컴포넌트의 관계를 맺어 주고, DOM을 업데이트한다.

3. Javascript를 사용해서 클라이언트 컴포넌트에 hydrate를 해 주어 상호작용이 가능하게 해 준다.

 

Next.js의 서버 렌더링 방식은 세 가지가 있다.

1. Static Rendering

기본값이며, 빌드 타임 혹은 data revalidation 후에 렌더링되고 이를 재사용한다. 개인정보 등이 아니라 누구나 같은 페이지를 보여주어야 할 때 빠르고 유용하다. 결과는 캐시되며 CDN에 넣을 수도 있다. 추후 ISR(Incremental Static Regeneration)을 통해 데이터가 업데이트될 수 있다.

2. Dynamic Rendering

클라이언트가 요청할 때마다 렌더링된다. Dynamic API나 { cache: 'no-store' } 옵션과 함께 fetch를 사용하면 자동으로 Dynamic Rendering으로 바뀐다. Dynamic API에는 connection, draftMode, searchParams, unstable_noCache 등이 있다. Dynamic Rendering이라고 해서 캐싱되지 않는다는 뜻은 아니며, 선택할 수 있다. 보통은 Static Rendering을 사용할 것이냐, Dynamic Rendering을 사용할 것이냐를 개발자가 고민하고 결정할 필요는 없으며 필요에 따라 개발하다보면 Next.js가 알아서 결정해줄 것이다.

3. Streaming

전체 완성된 페이지를 보여주는 것이 아니라 조각조각 잘라 완성되는 대로 클라이언트에게 보여준다. 여러 컴포넌트 중 느린 network call을 하는 컴포넌트가 있다면, 다른 컴포넌트들은 이 느린 컴포넌트와 관계 없이 먼저 보여줌으로써 유저에게 빠르다는 느낌을 줄 수 있다.  app router에서 loading.js와 React Suspence를 사용하면 적용된다. 

 

Static은 속도가 빠르나 개인화된 데이터를 보여주는 데 사용할 수 없고, Dynamic은 속도가 느리나 개인화된 데이터를 보여주는 데 사용할 수 있다. Streaming은 Dynamic Rendering을 써야 하는데 점진적인 렌더링을 적용함으로써 느린 속도를 보완한 것으로 보인다.

 

'프론트엔드 > Nextjs' 카테고리의 다른 글

Dynamic Route  (0) 2025.01.08
Parallel Route  (0) 2025.01.07
1. 프로젝트 생성과 디렉토리 구조  (0) 2023.12.25

Parallel Route (병렬 라우팅)

- 한 페이지 안에, 하나의 레이아웃 안에 여러 작은 페이지를 렌더링하고 싶을 때 사용한다. '여러 작은 페이지'는 <article>처럼 분리 가능한 구획이라고 생각하면 되겠다. Next.js에서는 이것을 'slot'이라고 부른다.

 

- 동시에 렌더링하기 때문에, fetch와 같은 네트워크 콜로 인한 waterfall을 방지할 수 있다. 

ex) 부모 컴포넌트에서 fetch를 호출하면, 자식 컴포넌트들 중 해당 fetch와 관계 없는 컴포넌트들도 부모의 fetch가 끝날 때까지 기다려야 렌더링이 된다. Next.js의 병렬 라우팅을 사용하면 '동시에' 렌더링되기 때문에 컴포넌트들을 관심사에 따라 분리할 수 있다.

 

- 문법은 부모 페이지 하위에 디렉토리를 생성한 후 디렉토리명 앞에 @를 붙인다. 디렉토리 하위에는 page.tsx가 있어야 한다. 부모 컴포넌트 하위에 layout.tsx에 slot을 children와는 별도로 렌더링한다. 

ex) app/dashboard/@user/page.tsx

 

- 위 path에서 @user는 실제 url로 만들어지지는 않는다. => localhost:3000/dashboard로 접근할 수 있다. 

 

- 각 slot에 하위 페이지를 생성할 수 있다. 탭 이동에 용이하다. 생성 방법은 하위에 디렉토리를 만들면 되는 식으로 app router 기본 방식과 동일하다.

 

- default.js 란?

어떤 페이지 안에 A slot과 B slot이 있고 A slot 하위에 a 페이지와 b 페이지를 탭으로 생성했다. 디렉토리 형태는 아래와 같을 것이다.

- parentPage

  - @A

     - a

        page.tsx

     - b

        page.tsx

  - @B

  layout.tsx

  page.tsx

 

정상적(?)인 루트대로 pageParent에 접근하고, A slot에서 b 탭을 클릭하면 b 탭은 'active'하게 된다. 이 때 @B는 별다른 행위를 취할 필요 없이 pageParent에 접근했을 때 렌더링했던 대로 있게 된다.

 

하지만 만약 이 상태에서 새로고침을 하게 되면 어떻게 될까? path는 `parentPage/b`가 된다. 어쨌든 페이지는 `pageParent`이므로 @A와 @B를 모두 렌더링한다. 그런데 path는 `parentPage/b`, 즉 b가 포함되어 있으므로 각 slot은 하위 페이지를 찾아서 렌더링해야 한다. @A는 문제가 없지만 @B에는 b 페이지가 없으므로 문제가 된다. 이 때 default.js를 만들어서 @B 하위에 넣어두면 이럴 때 렌더링할 fallback을 지정해둘 수 있다.

 

 

 

'프론트엔드 > Nextjs' 카테고리의 다른 글

Dynamic Route  (0) 2025.01.08
서버 렌더링  (0) 2025.01.07
1. 프로젝트 생성과 디렉토리 구조  (0) 2023.12.25

nextjs로 프로젝트 생성을 할 수 있는 방법에는 2가지가 있다. 하나는 create-next-app을 사용하는 방법이고, 다른 하나는 직접 수동으로 생성하는 방법이다.

create-next-app은 자동으로 package.json 작성 및 디렉토리 구조를 생성해줄 뿐만 아니라 next.js 개발자들에 의해 유지보수 된다고 하니 이 방법을 추천한다. 

 

npx create-next-app@latest
yarn create next-app
pnpm create next-app
bunx create-next-app

 

npm 외에 다른 패키지 매니저를 쓰고 싶으면 위에 써놓은 대로 해도 되고, npx create-next-app@latest 뒤에 --use-yarn, --use-pnpm 등을 입력하면 된다.

 

그 외에도 여러가지 옵션이 있지만 위에 작성된 명령어까지만 쳐도 터미널에 인터랙티브하게 설정할 수 있는 옵션들이 뜨니까 거기서 원하는대로 설정하면 된다.

 

이번에는 next.js의 샘플을 연습할 것이므로 아래와 같은 명령어를 사용했다.

pnpm create next-app nextjs-dashboard --example "https://github.com/vercel/next-learn/tree/main/dashboard/starter-example"

 

 

pnpm을 사용해서 nextjs-dashboard라는 이름의 프로젝트를 생성하는데, https://github.com/vercel/next-learn/tree/main/dashboard/starter-example 에 있는 샘플을 포크할 것이라는 뜻이다. 

 

이렇게 하면 nextjs-dashboard라는 디렉토리가 하나 생성되고 프로젝트가 만들어진다. 하위 디렉토리도 자동으로 생성되어 있는데, 구조는 아래와 같다.

- /app : 페이지 및 컴포넌트. (예전에는 페이징을 pages라는 디렉토리를 통해서 했지만 버전이 업그레이드되면서 app 방식을 제공)

- /app/lib : 재사용 가능한 함수들, 유틸리티 등의 js를 넣어두는 곳

- /app/ui : 카드 컴포넌트, 테이블 컴포넌트 등 작은 단위의 ui 컴포넌트를 넣어두는 곳

- /public : 정적인 에셋을 넣어두는 곳

- /scrips : 튜토리얼 따라가다보면 나중에 나올 스크립트 작성하는 곳

 

아무튼, 서버를 실행하기 위해서는 npm i && npm run dev를 터미널에 입력하면 된다. 

https://localhost:3000 에 들어갔을 때 이상한 사이트(아직 css가 적용되지 않음)가 나오면 성공!

'프론트엔드 > Nextjs' 카테고리의 다른 글

Dynamic Route  (0) 2025.01.08
서버 렌더링  (0) 2025.01.07
Parallel Route  (0) 2025.01.07

+ Recent posts