본문 바로가기

개발/Next.js

Next.js App Router

App Router 핵심 기능

  1. 페이지 라우팅 설정 방식 변경
  2. 레이아웃 설정 방식 변경
  3. 데이터 페칭 방식 변경
  4. React 18 신규 기능 추가 - React Server Component, Streaming

 

1. App router 에서의 페이지 라우팅 설정

이전 Page Router와는 다소 다른 폴더구조를 지니고 있다.

Next.js 이전 버전에서는 pages폴더 아래에 라우팅하고 싶은 경로들을 폴더로 만들었다면 App router는 따로 pages폴더가 없고 바로 app폴더 아래에서 라우팅하고 싶은 경로들을 폴더로 만들어줘야 하며, 또한 경로로 지정한 폴더 내에 파일명을 index.tsx 가 아닌, page.tsx로 지정해줘야 한다. 이건 Next.js App Router의 규칙이니 우리는 이 규칙대로 사용해야만 한다.

 

Page Router에서 사전렌더링 방식에선 여러 함수(getServerSideProps,getServerSideProps)들을 export하여 파라미터를 전달받아사용했는데, App Router는 어떻게 이런 파라미터들을 전달받아 사용할까?

생각보다 간단한데, 코드를 통해 살펴보자.

// // App Router
export default function Page({
  params,
}: {
  params: { id: string | string[] };
}) {
  return <div>book/[id]의 페이지 {params.id}</div>;
}

----

// Page Router => src/pages/book/[id].tsx
export const getStaticProps = async (context: GetStaticPropsContext) => {
  const id = context.params!.id;
  console.log(id) // 9
};

로컬 환경에서 http://localhost:3000/book/9 로 9번 아이디를 가진 책 정보 페이지에 접근했을때 해당 9번의 아이디를 읽어들이기 위해선, 기존 Page Router에선 사전렌더링을 통해. getServerSideProps나 getStaticProps 함수 내에서 id를 뽑아왔다면, App Router에선 바로 페이지 컴포넌트 내에서 params객체에 접근해서 가져올 수있다.

 

 

2. App Router에서의 레이아웃 설정하기

레이아웃은 내가 설정하고 싶은 폴더 아래에 layout.tsx 파일명으로 만들어서 관리해주면 되는데, 위와 같이. 래이아웃을 중첩해서도 관리할 수 있다.

 

app 폴더 아래에 인덱스 페이지와 search페이지에서 똑같은 레이아웃을 사용하고 싶다면.. 뭐 물론 아래와 같이 같은 폴더 아래에 레이아웃 파일을 만들어도 되지만, 유지보수 . 재사용을 위해, Next.js에서 라우트 그룹 이라는 기능을 사용하면 더욱 편리하게 관리할 수 있다.

경로 마다 모두 page.tsx, layout.tsx 만들기

위와 같은 폴더 구조와 달리 소괄호로 관리 되어지는 라우트 그룹 이라는 기능을 사용하면 된다.

아래와 같은 방식으로 소괄호로 폴더를 감싸게되면 이 폴더는 경로상 아무런 영향이 없는 폴더가 되버린다.

즉, 경로상 영향 없이 레이아웃만 동일하게 줄 수가 있다.

Next.js에서 위와 같은 폴더 구조를 가져가게 되면, 인덱스페이지와 서치페이지에는 동일한 임시서치바 텍스트가 보이지만,

book 폴더는 (with-searchbar) 경로에 담겨있지 않아 임시서치바가 안보인다.

 

3. 리액트 서버 컴포넌트

JS Bundle을 구성할때 상호작용하지 않은 컴포넌트도 Bundle에서 다시 관리되는 문제를 해결하기 위해 서버 컴포넌트를 이용한다.

즉, 서버측에서만 실행되는 컴포넌트들은 → 서버 컴포넌트라고 얘기한다

상호작용이 있어서 Hydration이 필요하기 때문에, 서버와 클라이언트에서 한 번씩 실행이 되어야할때 → 클라이언트 컴포넌트

 

서버 컴포넌트 그럼 언제 실행되는거지 ? Next.js 서버측에서 브라우저로부터 접속 요청을 받아 사전렌더링을 진행할때 클라이언트 컴포넌트와 함께 실행된다.

(여기서 동시에 실행된다고 표현하긴 했지만 루트형태로 이루어진 Next.js 내부 컴포넌트들의 사전 렌더링과정 중에는 서버컴포넌트가 클라이언트 컴포넌트보다 더 빨리 실행이 된다.)

Next.js 공식문서에선 페이지의 대부분을 서버컴포넌트로 구성하고 클라이언트 컴포넌트는 꼭 필요한 경우 에만 사용할 것을 권장. (상호작용이 있어야할때만 클라이언트 컴포넌트.) 이렇게보면 서버 컴포넌트는 딱 한번만 실행하니 클라이언트 컴포넌트보다 성능상 좋아 보인다.

근데 그게 맞다. 서버컴포넌트는 서버쪽에서만 실행하기 때문에 당연히 성능상 좋을 수 밖에 없다.

 

클라이언트 컴포넌트 만들어보기

검색 서치바 기능은 클라이언트(사용자)가 검색어를 입력시 서버에 요청을 매 번 보내고 서버에선 그 결과를 클라이언트에 다시 전달해줘야 하는 상호작용이 필요하므로 이 컴포넌트는 클라이언트 컴포넌트로 만들어보자.

경로: src/app/(with-searchbar)/searchbar.tsx

"use client";

import { useState } from "react";

export default function Searchbar() {
  const [search, setSearch] = useState("");

  const onChangeSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSearch(e.target.value);
  };

  return (
    <div>
      <input value={search} onChange={onChangeSearch} />
      <button>검색</button>
    </div>
  );
}

 

맨 윗줄에 "use client" 문구를 입력해주면 이 컴포넌트는 더이상 서버컴포넌트가 아닌 클라이언트 컴포넌트로 인식된다.

 

이렇게 서버컴포넌트와 클라이언트 컴포넌트를 대략적으로 살펴보았는데, 결국 이 두 컴포넌트는 위와 같이 데이터를 다른 형식으로 보내게 된다.

주로 정적으로 상호작용하지 않는 Server Component - RSC payload 특별한 상황이 없다면 서버컴포넌트라고 보면 된다.

상호작용하는 Client Component - Js Bundle

 

 

서버컴포넌트 사용시 주의 사항

  1. 클라이언트 컴포넌트 자식으로 서버컴포넌트를 직접 임포트해서 호출하지 말자 → 따로 오류는 나지 않지만, 이렇게 사용할 경우 해당 서버컴포넌트는 내부적으로 클라이언트 컴포넌트로 변환되어 동작하기 때문에 성능저하로 이어질 수 있다.
  2. 클라이언트 컴포넌트는 클라이언트에서만 실행되는게 아닌, 사전렌더링 작업을 위한 서버단에서도 실행이 된다.
  3. 서버 컴포넌트에는 브라우저에 실행되는 코드가 포함될 경우 에러가 난다. (서버에서만 실행되니 당연한 얘기인듯 싶다.)
  4. 서버 컴포넌트에서 클라이언트 컴포넌트에게 직렬화되지 않는 Props는 전달이 불가능하다. (직렬화되지 않는 props? 객체,배열,클래스 등의 복잡한 구조의 데이터를 네트워크 상으로 전송하기 위해 단순한 형태(문자열, Byte)로 변환하는 것) ⇒ 전달하고자 하면 런타임에러가 발생하니 주의하자.
    1. 여기서, 함수는 직렬화가 불가능하다. 함수는 값이 아닌 코드블럭을 포함하고 있는 특수한 형태이며 클로저,렉시컬스코프 다양한 환경에 의존되어 있기 때문이다. 이렇게 복잡한 구조로 이루어져 있는 함수들은 단순한 형태로 변경하지 못하기 때문에 함수는 직렬화가 되지 않아 props로 전달이 불가능!

 

 

 

출처: 한 입 크기로 잘라먹는 Next.js

 

한 입 크기로 잘라먹는 Next.js(15+) 강의 | 이정환 Winterlood - 인프런

이정환 Winterlood | 한입 시리즈의 3번째 작품! 세상에서 가장 친절하고 디테일 한 Next.js(15+)강의 입니다. App Router 뿐만 아니라 Page Router까지 프로젝트를 통해 살펴봅니다., [임베딩 영상]한 입 크기

www.inflearn.com