현 프로젝트에서 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에 직접 전달할 수 없다!
'source-code > Next JS' 카테고리의 다른 글
[next js] server component 페이지 route 속도 개선하기 (with streaming) (1) | 2024.07.23 |
---|---|
[next js] App Router Fetch Cache가 동작하지 않을 때 (0) | 2024.03.11 |
localhost fetch시 ECONNREFUSED 에러 해결하기 (0) | 2024.03.07 |
[next js] app directory에서 token 저장하기 (0) | 2024.02.13 |
[next js] server component로 httpOnly cookie 접근하기 (0) | 2024.02.06 |