본문 바로가기
source-code/Next JS

next js 13 변경사항 살펴보기

by mattew4483 2023. 8. 17.
728x90
반응형

현 프로젝트에서 next js 13 버전을 사용 중이다.

공식 문서를 보며 이전 버전에서 달라진 점 or 추가된 기능을 알아보자.

Project Structure

공식 문서에 명시된 프로젝트 구조.

Top-level files

Next.js  
next.config.js Configuration file for Next.js
middleware.ts Next.js request middleware
.env Environment variables
.env.local Local environment variables
.env.production Production environment variables
.env.development Development environment variables
.next-env.d.ts TypeScript declaration file for Next.js
Ecosystem  
package.json Project dependencies and scripts
.gitignore Git files and folders to ignore
tsconfig.json Configuration file for TypeScript
jsconfig.json Configuration file for JavaScript
.eslintrc.json Configuration file for ESLint

Top-level folders

app App Router
pages Pages Router
public Static assets to be served
src Optional application source folder

app 이라는 Top-level folder와, App Router란 용어가 등장했음을 확인할 수 있다.

 

App Router vs Pages Router

이전 버전까지는 page route는 Pages라는 폴더 내에, 해당 url의 폴더 명을 만드는 방식으로 이뤄졌다.

13 버전부터는 app 이라는 폴더를 통해 해당 기능을 구현된다.

 

app Routing Conventions

Routing Files

layout .js .jsx .tsx Layout
page .js .jsx .tsx Page
loading .js .jsx .tsx Loading UI
not-found .js .jsx .tsx Not found UI
error .js .jsx .tsx Error UI
global-error .js .jsx .tsx Global error UI
route .js .ts API endpoint
template .js .jsx .tsx Re-rendered layout
default .js .jsx .tsx Parallel route fallback page

내부 file들은 다음과 같다.

이 중 눈여겨 볼 부분은 page 파일과 layout 파일.

 

page

기존 Page Router 방식에서는 index라는 파일명을 해당 페이지에서 띄워줬으며,

파일 이름에 해당하는 url에서 해당 파일을 띄워줬다.

(ex page/main/hello.tsx => page/main/hello)

 

변경된 App Router 방식은 각 폴더명이 해당 url과 같으며,

해당 url에서 띄워줄 파일은 page 란 이름이어야 한다.

(ex page/main/hello/hello.tsx => page/main/hello)

 

layout

layout 파일을 통해 다른 routes간 같은 UI를 공유할 수 있다.

동일 layout을 공유하는 route간 이동이 발생하더라도, 해당 파일은 re-render되지 않는다.

 

app 폴더는 반드시 root layout file을 포함해야하며,

root layout 파일은 반드시 <html>, <body> tag를 정의해야 한다.

이때 <head> tag(<title>, <meta>등)를 임의로 추가해서는 안되며, next의 Metadata API를 이용해 이를 정의할 수 있다.

(기존 _app 파일을 대체)

React Essentials

Server Components

React 18의 Server-Component를 통해 특정 컴포넌트들을 서버에서 rendering 할 수 있게 되었다.

server-component를 사용함으로써

서버 인프라 활용 및 성능 향상, client-side bundle 크기 줄임, 초기 페이지 로드 향상 등의 이점을 가질 수 있다.

→ next 13에서는 기본적으로 모든 컴포넌트가 server-component 이다.

만약 client-component를 채택하고 싶다면 해당 파일 최상단에 'use client' 지시문을 작성해 주면 된다.

 

그렇다면 어떨 때 server-component를, 어떨 때 client-component를 사용해야 할까?

이를 통해 코드 작성 시 다음과 같은 사항들을 유의해야 함을 알 수 있다.

1. user-interaction 발생 컴포넌트와, 그렇지 않은 컴포넌트와의 명확한 구분

유저와의 상호작용이 일어나지 않는데도, 불필요한 state나 lifecycle effect hooks를 사용해서는 안된다.

→ 컴포넌트 관심사 분리의 중요성이 더욱 증대.

 

2. data fetching 전략

이전 react 아키텍처 중 presentational / container component와 유사하다 볼 수 있겠다.

즉 user interaction, style과 관계없이 server로부터의 data fetching을 담당하는 server-component와,

사용자 행위에 영향을 받거나 browser api를 사용하는 client-component로 구분해 컴포넌트들을 설계해야 할 테다.

 

3. client component를 tree의 leaf에 위치

애플리케이션의 성능 개선을 위해(가능한 server component를 사용하기 위해)

client-component를 component tree의 가능한 끝에 위치해야 한다.

// SearchBar is a Client Component
import SearchBar from './searchbar';
// Logo is a Server Component
import Logo from './logo';
 
// Layout is a Server Component by default
export default function Layout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      <nav>
        <Logo />
        <SearchBar />
      </nav>
      <main>{children}</main>
    </>
  );
}

Layout전체를 client-component로 만든 것이 아니라

Logo와 같은 static 요소들은 server-component로,

SearchBar와 같은 user interaction이 발생하는 요소는 별도의 client-component로 작성한 모습!

 

React는 두 코드를 다음과 같은 방식으로 합성한다.

1) server에서 모든 server-component들을 render (해당 결과를 client에 보내기 전)

이때, Client-Component와 중첩된 Server-Component들도 모두 포함된다.

해당 과정에서 Client-Component는 skip!

2) client에서 server-component에서 렌더링 된 결과와 client-component의 render 결과를 병합

 

Client-Component와 중첩된 Server-Component들은 client-component속 해당 자리에 위치하게 된다.

 

4. children props

client-component의 구성 요소로 server-component를 가져올 수 없다.

// ServerComponent.tsx
const ServerComponent = () => <div/>


// ClientComponent.tsx
'use client'
const ClientComponent = () => {
	return (
    	<>
        	<button/>
        	<ServerComponent/> // Err
        </>
    )
}

그렇다면 client-component에서는 server 측에서 render 할 수 있는 코드들도 몽땅 client에서 실행해야 하나?

// ServerComponent.tsx
const ServerComponent = () => <div/>


// ClientComponent.tsx
'use client'
const ClientComponent = ({children}:{children:ReactNode}) => {
	return (
    	<>
        	<button/>
        	{children} // Err
        </>
    )
}


const Page = () => {
	return (
    	<ClientComponent>
        	<ServerComponent/>
        </ClientComponent>
    )
}

children props를 통해 특정 컴포넌트를 주입하는 형태로 해당 컴포넌트를 설계할 수 있겠다.

 

위와 같이 작성할 경우

server-component는 서버에서 렌더링 되고

client-component가 클라이언트에서 렌더링 될 때, 해당 구멍(hole)이 server에서 렌더링 한 컴포넌트로 채워지는 것!

 

 

Passing props from Server to Client Componts (Serialization)

server-component에서 client-component에 넘겨줄 수 있는 데이터는 serializable 해야 한다.

 functions, Dates 등은 client-component에 직접 전달할 수 없다!

728x90
반응형