Front-End/Next

Next.js App Router

Voyage_dev 2024. 8. 6. 01:26
✔️ Next.js 앱 라우터의 개념과 Page, Layout에 대해서 살펴보자

 

Next 12 버전까지는 페이지 라우터 방식이 기본 방식으로 잘 사용되어 왔다. 기존의 페이지 라우터 방식을 잘 사용하고 있었는데 왜 13 버전부터는 앱 라우터라는 새로운 라우터 방식이 나왔을까?

 

Page Router 방식의 한계

모든 페이지에 들어가는 <Header /> 컴포넌트를 Next.js 페이지 라우터 방식으로 구현을 하기 위해서는 어떻게 해야 할까?

  • 각각의 페이지 컴포넌트에 <Header />를 일일이 넣는다 (권장하지 않는다)
  • _app, _document 같은 파일에 <Header />를 넣는다

이전에 살펴본 _app, _document의 목적

  • _app : 페이지를 초기화하기 위한 용도로 사용
    • 페이지 변경 시 유지하고 싶은 레이아웃
    • 페이지간 추가적인 데이터 삽입
    • global CSS 주입
  • _document : 페이지에서 쓰이는 <html>, <body> 태그를 수정하거나, SSR 시 styled-components 같은 일부 CSS-in-JS를 지원하기 위한 코드 삽입 하는 제한적인 용도로 사용

이러한 <Header />가 모든 페이지에서 다 들어간 경우도 있지만 일부 페이지에서만 들어가게 되는 경우 예를 들어 A,B,C 페이지에서는 들어가지만 D,E 넣지 않을 때 즉, 일부 특정 컴포넌트에서만 넣어줘야 된다라고 한다면 앱이나 도큐멘트에서 사용하는 것은 살짝 무리가 있을 수가 있다. 그리고 프로젝트가 복잡해질수록 이렇게 여러 컴포넌트에서 같이 써야 되는 컴포넌트들이 굉장히 많아질 수가 있다. 근데 그거를 모두 앱이나 도큐멘트에서 관리를 하게 된다면 복잡도가 굉장히 높아지고 좋지 않은 구조가 될 가능성이 높다.

 

기본에 페이지 라우터 방식은 공통 레이아웃을 유지하는데 한계가 있다

→ 이러한 한계를 극복하기 위해 나온 것이 바로 app 레이아웃이다

 

설치

App Route는 Next 13.4 버전부터 정식 기능으로 릴리즈

npx create-next-app@latest
  • TypeScript : Y
  • ESLint : Y
  • Tailwind CSS (옵션)
  • /src directory : N
  • App Router : Y
  • import alias : N

가장 큰 변화

  • 기존에 /pages 로 정의하던 라우팅 방식이 /app 디렉터리로 이동했다는 점
  • 파일 명으로 라우팅 하는 것이 불가능했졌다는 점

layout.tsx

 

create-next-app로 우리가 보일러 플레이트로 프로젝트를 생성했을 때 기본으로 만들어지는 파일 중에 하나이다. 이 파일의 목적은 페이지의 레이아웃을 구성하는 요소로서 역할을 하고 있다. 즉, 어떤 폴더에 app 이라는 디렉터리가 있는데 이 폴더에 레이아웃이 있다면 이 레이아웃은 이 폴더 그리고 이 폴더의 하위 주소에 모두 영향을 미친다.

  • 기본으로 만들어지는 파일
  • 이 파일은 페이지의 기본적인 레이아웃을 구성하는 요소
  • 루트에는 단 하나의 layouy을 둘 수 있다
  • 이 layout은 모든 페이지에 영향을 미치는 공통 레이아웃
  • 페이지 하위에 추가되는 layout은 해당 주소 하위에만 적용
  • layout은 주소별 공통 UI를 포함할 수 있을 뿐 아니라 _app과 _document를 대신해 웹 페이지를 시작하는데 필요한 공통 코드 삽입

주의점

  • 이 레이아웃은 앱 디렉터리 내부에서 사용하는 예약어이다. Next.js 에서 지정된 예약어이기 때문에 무조건 레이아웃을 사용해야 한다. 즉, 다른 목적으로는 사용할 수가 없다.
  • 레이아웃은 children을 받아서 뿌려주는 역할을 하고 있다. 그래서 우리가 만들어야 되는 컴포넌트는 외부에서 주입을 받아서 그려야 한다.
  • 레이아웃 컴포넌트는 반드시 export default로 내보내는 컴포넌트를 가지고 있어야 한다.
  • API와 같은 비동기 작업도 할 수 있다.

page.tsx

  • 기본으로 만들어지는 파일
  • page는 앞에서 구성했던 layout을 기반으로 리액트 컴포넌트 노출
  • page가 받는 props
    • params : 옵셔널 값, […id]와 같은 동적 라우트 파라미터 사용 시 값이 들어온다
    • searchParams : ?a=1 과 같은 URLSearchParams값을 의미한다
      • 이 값은 layout에서는 제공되지 않는다. 왜냐하면 layout은 페이지 탐색 중에 리렌더링을 수행하지 않기 때문이다.

공식문서

https://nextjs.org/docs/app/building-your-application/routing

https://nextjs.org/docs/app/building-your-application/routing/defining-routes

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

  • page.js : 라우트에 유니크한 UI 컴포넌트
  • layout.js : 여러 라우트에 걸쳐서 공유되는 UI 컴포넌트
  • template.js : 레이아웃과 비슷한 요소
    • 레이아웃과 차이점은 레이아웃이 라우트를 거쳐가면서 상태를 유지한다면
    • 템플릿은 매번 새로운 인스턴스를 만든다
    • 이 말은 사용자가 라우트 간에 템플릿을 공유하면, 새로운 컴포넌트가 보여지고 , DOM은 재생성되며, 상태는 보존이 안되고, 효과는 다시 동기화가 된다.
✔️ 링킹, 네비게이팅, 에러 핸들링에 대해서 살펴보자

 

링킹 & 네비게이팅

 

라우트 네비게이션을 할 수 있는 4가지 방법

https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating

 

Routing: Linking and Navigating | Next.js

Learn how navigation works in Next.js, and how to use the Link Component and `useRouter` hook.

nextjs.org

  • Link 컴포넌트 (가장 권장)
  • useRouter 훅 (클라이언트 컴포넌트)
  • redirect 함수 (서버 컴포넌트)
  • History API

에러 핸들링

 

Error.js 동작원리

https://nextjs.org/docs/app/building-your-application/routing/error-handling

 

Routing: Error Handling | Next.js

Handle runtime errors by automatically wrapping route segments and their nested children in a React Error Boundary.

nextjs.org

Next.js 에러 핸들링은 기본적으로 중접된 라우트를 기본으로 사용하고 런타임에서 오류를 좀 우아하게 처리를 하는 방식을 지향하고 있다. 그래서 Error를 처리할 때 그냥 Error가 났다고 바로 Error 페이지로 이동하는게 아니라 Error가 발생한 그 레이아웃 그리고 그 Error가 영향을 받는 자식 컴포넌트들을 기반으로 Error에 대한 처리를 할 영역을 경계를 랩핑하는 작업을 첫 번째로 하게 된다.

 

그래서 이 랩핑 된 이 영역 외에 다른 부분은 정상적으로 동작을 할 수 있게 만드는 것이 Next.js의 Error 핸들링의 중요한 원칙 중의 하나이다. 즉, 전체 페이지를 다 다시 로드하는게 아니라 Error에서 회복을 할 수 있는, 리커버를 할 수 있는 기능을 줌으로써 잘 사용되던 기능들을 제대로 최대한 살리고 Error가 난 부분만 빠르게 복구할 수 있게 하는 전략을 가져가고 있다. 그리고 Error가 발생했을 때 Error를 대체할 그런 대체 컴포넌트들을 활성화 시켜준다.

  • 라우트와 자식 컴포넌트를 기준으로 에러를 처리할 경계를 래핑
  • 영향을 받는 범위가 아닌 다른 부분은 정상적으로 동작 가능
  • 전체 페이지를 다시 로드하는 것이 아닌, Error에서 recover 기능 추가
  • Error 발생 시 대체 컴포넌트를 활성화, 상호작용이 가능하며 reset 기능 추가
✔️ 라우트 그룹, 병렬 라우트 등에 대해서 살펴보자

 

라우트 그룹

https://nextjs.org/docs/app/building-your-application/routing/route-groups

 

Routing: Route Groups | Next.js

Route Groups can be used to partition your Next.js application into different sections.

nextjs.org

 

  • 우리가 폴더 구조를 만들고 경로를 만들 때 모든 경로를 다 필요로 하지는 않을 때가 있다. 어떤 경로는 빼야 되는 상황도 있을 수가 있다. 이때 우리가 App Router에서 사용되는 개념이 바로 라우트 그룹이다.

폴더를 라우트 그룹으로 표시하여 라우트의 URL 경로에 폴더가 포함되지 않도록 할 수 있다.

→ 이를 통해 URL 경로 구조에 영향을 주지 않고 라우트 세그먼트와 프로젝트 파일을 논리적 그룹으로 조작할 수 있다.

 

e.g.

  • app/(marketing)/account → /account
    • 앱 디렉토리에 marketing 이라는 폴더를 만들고 그 하위에 account라는 폴더를 만들어서 거기에서 페이지나 레이아웃이라는 컴포넌트를 만들었을 때 marketing에 해당되는 이 폴더명을 쓰고 싶지 않다 라고 한다면 이 폴더를 이렇게 () 괄호 처리를 해줄 수가 있다.
    • 그러면 이 account 안에 있는 페이지 컴포넌트나 레이아웃 컴포넌트는 경로를 marketing account가 아니라 그냥 account로 받게 된다.
    • 이렇게 라우트 그룹을 통해서 사용하지 않는 경로 구조를 필요에 따라서 제거해 줄 수 있다.
❗ 라우트 그룹을 포함하는 라우트는 다른 라우트와 동일한 URL 경로로 해석되어서는 안된다

예를 들어, 라우트 그룹이 URL 구조에 영향을 주지 않기 때문에, (marketing)/about/page.js와 (shop)/about/page.js는 모두 /about 으로 해석되어 오류를 일으킬 수 있다

 

병렬 라우트

https://nextjs.org/docs/app/building-your-application/routing/parallel-routes

 

Routing: Parallel Routes | Next.js

Simultaneously render one or more pages in the same view that can be navigated independently. A pattern for highly dynamic applications.

nextjs.org

 

병렬 라우트는 동일한 레이아웃 내에서 하나 이상의 페이지를 동시에 또는 조건부로 렌더링을 할 수 있게 해준다. 이는 보통 대시보드나 소셜 사이트의 피드 같은 앱에서 동적인 섹션을 만들 때 굉장히 유용하게 사용이 된다.

병렬 라우트는 명명된 슬롯을 사용하여 생성한다.

  • 슬롯은 @이라는 특수문자를 붙이는 폴더 규칙으로 정의
  • 슬롯은 라우트 세그먼트가 아니며, URL 구조에 영향을 주지 않는다

https://nextjs.org/docs/app/building-your-application/routing/parallel-routes

 

이렇게 앱 디렉토리 하위에서 @team 이라는 이름의 병렬 라우트 슬롯 그리고 @analytics라는 슬롯을 만들고 둘 다 이렇게 페이지라는 이름으로 페이지 컴포넌트를 만들었을 때 이 요소들을 다음과 같이 레이아웃에서 두 개를 동시에 보여주는 병렬 라우팅을 처리를 할 수가 있다.

Next.js는 각각의 슬롯에 대해서 활성 상태 추적을 하고 있다. 그런데 이 슬롯 안에서 렌더링이 되는 컨텐츠는 어떠한 타입의 네비게이션에 의해서 이루어지는지에 따라서 렌더링 되는 방식이 조금 달라진다. 크게 두 가지 네비게이션 방식이 있다.

  • Soft Navigation : 클라이언트 측에서 네비게이션을 하는 과정에서 Next.js가 부분적인 렌더링을 수행을 하고 슬롯 안에 있는 하위 페이지들을 변경을 해주게 된다. 그리고 그 동안에 지금 URL과 일치하지 않더라도 다른 슬롯에 활성된 하위 페이지를 유지하는 과정이 바로 Soft Navigation의 방법이다.
  • Hard Navigation : 전체 페이지를 로드하고 나서 Next.js는 지금 URL과 일치하지 않는 슬롯의 활성 상태를 결정하지 않는다. 대신에 일치하지 않은 슬롯은 디폴트 파일을 통해서 렌더링을 하거나 디폴트 파일이 없으면 404를 통해서 렌더링을 하는 방식으로 사용이 된다.

병렬 라우트를 통해서 여러 가지 작업들을 할 수가 있는데 그중에 대표적인 작업이 바로 조건부 라우트이다.

 

조건부 라우트

https://nextjs.org/docs/app/building-your-application/routing/parallel-routes

 

  • 어떤 조건에 따라서, 특히 대시보드 같은 서비스를 만들 때는 유저의 권한에 따라서 관리자 권한인지 일반 사용자 권한인지 등 이런 역할에 따라서 다른 컴포넌트를 보여줘야 될 때가 있다. 그런 경우에 조건부 라우트를 작업을 할 때 병렬 라우트를 사용할 수가 있다.

Tab Groups

https://nextjs.org/docs/app/building-your-application/routing/parallel-routes

  • 슬롯 안에서 레이아웃을 추가를 해서 사용자가 슬롯을 독립적으로 네비게이션 할 수 있도록 만들어서 Tap을 만드는데 굉장히 유용하게 사용할 수도 있다.

Modals

https://nextjs.org/docs/app/building-your-application/routing/parallel-routes

  • 병렬 라우트는 Intercepting Route와 함께 사용해서 modal을 만들어줄 수가 있다. 이렇게 했을 때 기존에 우리가 modal을 만들면서 가지고 있었던 여러가지 문제들을 해결할 수가 있게 된다. 예를 들면 modal 컨텐츠를 우리가 URL을 공유함으로써 그 modal 컨텐츠도 같이 공유를 할 수가 있게되고 페이지를 새로고침 할 때 modal이 닫히지 않고 컨텍스트를 유지하게 만들 수도 있다. 그리고 modal을 닫을 때 이전 상태 / 이전 페이지로 되돌아가는 네비게이션을 통해서 modal을 닫을 수도 있고 앞으로 탐색을 할 때 modal을 다시 열 수도 있다.
병렬 라우트는 Next.js 앱 라우터 방식에서 새롭게 추가된 여러 컴포넌트들을 동시에 또는 조건부로 설정해 줄 수 있는 방법이다. 이 방법을 통해서 어떤 권한을 부여하거나 modal을 작업하거나 조건부로 라우팅을 해야 되는 작업들을 할 때 잘 사용하면 Next.js가 기존에 만들어 놓은 기능들을 통해서 여러 성능적인 측면에서 이점을 얻을 수 있다.