Next.js App Router(1/3)

김재한·2024년 1월 4일
1

Next 14

목록 보기
2/5
post-thumbnail

서론

X(구 트위터) 클론 코딩에서 App Router를 사용할 예정이라 이번 기회에 정리하고 넘어가려 한다.

Next.js 13버전에서 beta였던 App Router가 13.4버전에 들어서면서 Stable로 변경 되었다.

Next 공식 도큐먼트에도 Using App RouterUsing Pages Router 두 버전으로 나눠져 있는 것처럼 큰 차이가 있다고 생각한다.

아래 내용들은 Next App Router 공식문서를 정리하신 분의 글을 참고하여 구글링한 내용들을 더해 나에게 맞게 다시 정리했다.

App Router

기존 /pages 파일 시스템 기반의 라우팅 방법에서 /app 디렉토리 구조의 라우팅 방법으로 변화됨에 따라 공유 레이아웃, 중첩 라우팅, 로딩 상태, 에러 핸들링 등 유용한 기능들을 지원한다.

File Convention

UI를 핸들링할 수 있는 특정 파일명이 있다. 공식문서 참고

  • page.js: 경로(route)에 접근할 수 있는 파일이다 ( 12버전에서의 index.js )
    • route.js: route에 대해 server-side API 엔드포인트를 생성한다.
  • layout.js: 동일한 폴더 내에 있는 페이지들에 공통 UI를 생성한다.( 이전에는 _app.js을 사용했다. )
  • loading.js: 동일한 폴더 내에 있는 페이지들에 공통 로딩 UI를 생성한다.
  • error.js: 동일한 폴더 내에 있는 페이지들에 공통 에러 UI를 생성한다.
    • global-error.js: root의 layout.js에 대한 에러를 catch한다.
  • not-found.js: url에 일치하는 route가 없을 때 표시된다.

Component Hierarchy

Pages & Layouts

Page

  • page는 route에 대한 유니크한 UI이다.
  • 'use client'를 사용하지 않으면 default인 Server Component로 생성된다.
  • DATA Fetch가 가능하다.

Layouts

  • 하위 세그먼트에서 공유하는 공통 UI 이다. route 이동시 layout은 리렌더링 하지 않는다.
  • 중첩이 가능하며 부모 layout이 자식 layout을 감싸고 있다.
  • DATA Fetch가 가능하다.
  • 가장 상위에 있는 root Layout은 Server Component 이다.

부분렌더링

형제 관계인 route 사이에서 페이지 이동 시 이동하는 route의 page와 layout만 리렌더링 한다. 즉, 상위 route의 layout을 포함한 세그먼트들은 유지되어 불필요한 리렌더링을 방지할 수 있다.

Loading

loading.js 파일은 콘텐츠가 로드 되는 동안 서버로부터 즉각적인 로딩 상태를 보여주는 파일이다.

Modifying <head/>

title 태그나 meta 태그 같은 head 태그 내 HTML 엘리먼트는 내장 SEO 지원을 통해 변경이 가능하다.

Metadata는 레이아웃이나 페이지 파일에서 object나 generateMetadata 함수를 export해서 정의할 수 있다.

import { Metadata } from 'next';
 
export const metadata: Metadata = {
  title: 'Next.js',
};
 
export default function Page() {
  return '...';
}

이때 head 태그로 직접 선언하면 안되고 Metadata API를 사용해야 streaming 과 head 엘리먼트에 대한 중복제거가 된다고 한다.

Streaming

SSR은 아래와 같은 프로세스를 지나 사용자에게 보여진다

SSR 렌더링 과정

  • 데이터를 fetch 해 HTML 문서를 렌더링 한다.
  • 페이지에 대한 HTML, CSS, JS 파일들이 클라이언트에 전송된다.
  • HTML과 CSS로 생성된 non-interactive한 UI가 보여진다.
  • React가 Hydrate 되고 UI가 interactive하게 동작한다.

즉, 모든 데이터가 fetch 되어야 페이지에 대한 HTML을 렌더링 할 수 있다.

Streaming은 각각의 컴포넌트를 작은 chunk 단위로 나누어 점진적으로 전달하는 방식이다.

시간이 오래 걸리는 fetching 작업이 필요없는 컴포넌트 부터 화면에 보여지게 되면서 TTI(Time To Interactive)를 향상시킬 수 있다.

예시) Suspense를 사용해 점진적 렌더링

import { Suspense } from 'react';
import { PostFeed, Weather } from './Components';
 
export default function Posts() {
  return (
    <section>
      <Suspense fallback={<p>Loading feed...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>Loading weather...</p>}>
        <Weather />
      </Suspense>
    </section>
  );
}

Error Handling

error.js 는 route segment와 자식들을 React Error Boundary로 감싸 공통으로 처리할 수 있다.

특정 컴포넌트만 error처리할 수 있기 때문에 full page reload 없이 부분적으로 처리할 수 있다.

또한 error 컴포넌트는 'use client'를 명시해 Client Component로 사용해야한다.

'use client'; // client component
 
import { useEffect } from 'react';
 
type Props = {error: Error, reset:void} 

export default function Error({error, reset}: Props) {
  // reset: 사용자가 recover할 수 있게 error boundary내 콘텐츠를 re-render하는 함수를 제공한다.
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error);
  }, [error]);
 
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button
        onClick={
          // Attempt to recover by trying to re-render the segment
          () => reset()
        }
      >
        Try again
      </button>
    </div>
  );
}

error.js 작동 방식

error.js

코드에서 보는 것 처럼 error.js는 에러가 발생하면 보여지는 fallback Ui이고 layout의 child이기 때문에 동일한 segment 내의 layout의 오류는 catch 할 수 없다.
global 하거나 root의 오류를 핸들링 하기 위해서는 global-error.js를 사용해주면 된다.

Next.js App Router(2/3) ➡️

참조
Defining Routes
Pages and Layouts
Route Group
Loading and streaming
Error Handling
@khy226
@asdf99245

0개의 댓글