📘 Page Router 장점
📄 파일 시스템 기반의 간편한 페이지 라우팅 제공
- pages 폴더 안의 파일 구조에 따라 라우팅
- 동적 경로를 사용하는 다이나믹 페이지도 대괄호를 통해 하나의 URL 파라미터에 대응 가능
book/1
,book/2
,book/3
, ...
- catch-all segments: [..id]
- 중첩된 모든 URL 파라미터에 대응 가능
book/1
,book/2/100
,book/100/2345/233/5232
, ...
- optional catch-all segments: [[...id]]
- 인덱스 페이지까지 포함하면서 동시에 중첩된 모든 URL 파라미터에 대응 가능
book
,book/1
,book/2/100
,book/100/2345/233/5232
, ...
📄 다양한 방식의 사전 렌더링 제공
- 리액트의 느린 FCP라는 단점을 효과적으로 해결하기 위한 방식
- 브라우저로부터 접속 요청을 받았을 때 서버 측에서 직접 자바스크립트 코드를 실행해서 완성된 HTML 페이지를 미리 생성한다
- 생성한 HTML 페이지를 브라우저에게 응답함으로써 FCP를 효과적으로 단축하는 사전 렌더링 방식으로 동작한다
1.서버 사이드 렌더링 (SSR)
- 특징: 요청이 들어올 때마다 사전 렌더링을 진행한다
- 장점: 항상 최신의 데이터를 보장할 수 있다
- 단점: 데이터 요청으로 인해 응답 속도가 느릴 수 있다
2. 정적 사이트 생성 (SSG)
- 특징: 빌드 타임에 미리 페이지를 사전 렌더링 해둔다
- 장점: 사전 렌더링이 오래 걸리더라도 모두 서버 가동 이전에 빌드 타임에만 일어나는 일이기 때문에 빌드가 완료된 이후에 발생하는 접속 요청에는 미리 만들어둔 페이지를 통해 빠른 속도로 응답할 수 있다
- 단점: 빌드 타임 이후에 다시는 페이지를 재생성하지 않기 때문에 매번 똑같은 페이지만 응답해 최신 데이터를 반영하기 어렵다
3. 증분 정적 재생성 (ISR)
- SSG 페이지 일정 시간마다 재생성
- On-Demand 방식
- 유저의 특정 행동(게시글 수정 등) 이후에만 페이지를 다시 요청하고 싶으면 Revalidate 요청을 통해 페이지를 즉각적으로 다시 생성할 수 있게 설정 가능
📘 Page Router 단점
📄 페이지별 레이아웃 설정이 번거로움
- 레이아웃이 적용되길 원하는 페이지마다 getLayout()을 추가해야 한다
- 페이지별 레이아웃 설정이 많아지면 중복된 코드가 생기고 불필요하게 복잡하다
📄 데이터 페칭이 페이지 컴포넌트에 집중됨
- getServerSideProps, getStaticProps 등을 이용해 백엔드 서버로부터 데이터를 불러와 페이지 컴포넌트에 Props 형태로 데이터 전달해야 한다
- 페이지 컴포넌트에서는 Props로 데이터를 수신받아 사용한다
- 자식 컴포넌트의 자식 컴포넌트의 자식 컴포넌트.. 등 컴포넌트 깊이가 깊어지면 데이터를 계속 내려줘야 한다(Props Drilling )
📄 불필요한 컴포넌트들도 JS Bundle에 포함됨
FCP 시점 이후에 넥스트 서버가 브라우저에게 후속으로 Hydration을 위해 작성한 모든 컴포넌트들을 JavaScript 번들로 묶어서 전달하는 과정에서 굳이 브라우저에게 전달될 필요가 없는 불필요한 컴포넌트도 함께 포함되어 전달된다
- JavaScript Bundle의 용량이 불필요하게 커져 Hydration이 완료되는 시간이 오래 걸린다 -> TTI에 걸리는 시간까지 늦어진다
불필요한 컴포넌트?
- 상호작용하는 기능이 없어 브라우저에서 한 번 더 실행되어 Hydration이 될 필요가 없는 컴포넌트
- Next에서의 컴포넌트는 2번 실행된다
- 서버 측에서 사전 렌더링을 진행하기 위해 실행
- JavaScript 번들에 포함되어 브라우저에게 전달되어서 Hydration을 위해 한 번 더 브라우저 측에서 실행
Hydration 하는 이유?
- HTML로만 렌더링 되어 있던 페이지에 JavaScript 코드를 연결해서 상호작용(사용자의 클릭, 입력 등의 이벤트)을 추가하기 위함이다
📘 페이지 라우팅
pages 폴더 안의 파일 경로대로 라우팅
- localhost:3000/search → pages/search/index.tsx
- localhost:3000/book/13 → pages/book/[id].tsx
import { useRouter } from 'next/router';
const router = useRouter();
// 쿼리스트링
const { q } = router.query;
// 파라미터
const { id } = router.query;
- 파리미터가 하나일 때는 [id].tsx
- 파라미터가 여러 개일 때는 [...id].tsx
- ⇒ Catch All Segment
- 모든 구간에 대응하는 페이지를 만든다
- index(’/’) 경로에는 대응하지 못한다
- 해결 1: index.tsx를 추가로 만들어서 대응
- 해결 2: [[...id].tsx
- ⇒ Optional Catch All Segment
- 404 대응하기
- pages/404.tsx
📘 내비게이팅
다른 페이지로 이동하고 싶을 때
📄 a 태그
- CSR 방식으로 페이지를 이동시키는 게 아닌 서버에게 새로운 페이지를 매번 다시 요청하는 일방적인 방식
- 비교적 느린 방식
📄 Link 태그
import '@/styles/globals.css';
import type { AppProps } from 'next/app';
import Link from 'next/link';
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<header>
<Link href='/'>index</Link>
<Link href='/search'>search</Link>
<Link href='/book/1'>book/1</Link>
</header>
<Component {...pageProps} />
</>
);
}
📄 프로그래머틱한 페이지 이동
Programmatic Navigation
- 사용자가 직접 링크를 클릭했을 때 이동하는 방식이 아닌 특정 버튼이 클릭되었거나 특정 조건이 만족했을 경우에 어떠한 함수 내부에서 페이지를 이동시키는 방법
import '@/styles/globals.css';
import type { AppProps } from 'next/app';
import { useRouter } from 'next/router';
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter();
const handleButtonClick = () => {
router.push('/test');
};
return (
<>
<header>
<div>
<button onClick={handleButtonClick}>/test 페이지로 이동</button>
</div>
</header>
<Component {...pageProps} />
</>
);
}
- push: 이동
- replace: 뒤로가기를 방지하면서 이동
- back: 뒤로가기
📘 Pre-fetching
- pre: 사전에, fetching: 미리 불러온다
- 현재 사용자가 보고 있는 페이지에서 이동할 가능성이 있는 모든 페이지들을 사전에 미리 다 불러놓는다
- 빠른 페이지 이동을 위해 제공되는 기능
- Link 컴포넌트로 명시된 경로가 아니라면 프리페칭이 이루어지지 않는다
- 위 예시에서 /search, /book은 프리페칭이 되지만 /test는 프리페칭이 안된다
📗 /test도 프리페칭 하고 싶다면?
- router.prefetch
import '@/styles/globals.css';
import type { AppProps } from 'next/app';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter();
const handleButtonClick = () => {
router.push('/test');
};
useEffect(() => {
router.prefetch('test');
}, []);
return (
<>
<header>
<div>
<button onClick={handleButtonClick}>/test 페이지로 이동</button>
</div>
</header>
<Component {...pageProps} />
</>
);
}
📗 링크 컴포넌트의 프리페칭을 막고 싶다면?
- /search의 프리페칭 막기
- <Link href='/search' prefetch={false}>
import '@/styles/globals.css';
import type { AppProps } from 'next/app';
import Link from 'next/link';
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<header>
<Link href='/'>index</Link>
<Link href='/search' prefetch={false}>
search
</Link>
<Link href='/book/1'>book/1</Link>
</header>
<Component {...pageProps} />
</>
);
}
📘 API Routes
Next.js에서 API를 구축할 수 있게 해주는 기능
- 간단한 API를 구축해서 클라이언트(브라우저)로부터 요청을 받아 데이터베이스에서 데이터를 꺼내온다던가 또 다른 서드파티에서 데이터를 불러와서 전달한다던가 하는 동작을 할 수 있다
- pages/api 안에 있는 파일들은 API Routes로 웹페이지를 정의하는 파일이 아닌 API 응답을 정의하는 코드가 된다
- 자주 사용되는 기능은 아니다
📘 스타일링
- APP 컴포넌트가 아닌 파일에서는 import문을 통해 css 파일을 그대로 불러오는 걸 제한한다
- 별도의 페이지 파일에서 css 그대로 불러와서 import 하면 다른 페이지에 작성된 css 코드와 충돌 가능성이 있기 때문이다
📘 CSS 모듈
- 기존의 CSS 파일을 마치 모듈처럼 사용할 수 있도록 도와준다
- CSS 파일에 작성해 둔 클래스명이 다른 CSS 파일과 중복되지 않도록 자동으로 클래스명을 유니크한 이름으로 파일마다 변환을 시킨다
index.tsx
// CSS Module
import style from './index.module.css';
export default function Home() {
return (
<>
<h1 className={style.h1}>인덱스</h1>
</>
);
}
index.module.css
.h1 {
color: red;
}
.h2 {
color: blue;
}
[출처] 한 입 크기로 잘라먹는 Next.js
반응형
'Framework > Next.js' 카테고리의 다른 글
[Next.js] Next에서 svg 사용하기 (0) | 2024.10.22 |
---|---|
[Next.js] Page Router - 페이지 라우팅 설정 (1) | 2024.09.11 |