Next.js 13, Pages Router 을 기준으로 작성되었습니다.
페이지와 렌더링 방법
- pages 디렉터리 아래에 배치된 TSX 등의 파일은 파일 1개가 페이지 1개에 대응한다.
- 예를 들어,
pages/index.tsx
라는 파일은 /
에 접속했을 때 반환하는 페이지를 구현한 것이다.
- 이 파일들은 리액트 컴포넌트를 반환하는 함수를 정의하고, 그 함수를 익스포트 한다.
- 관습적으로 익스포트한 함수와 파일명은 동일하게 작성한다.
- 다음과 같이
pages/sample.tsx
를 작성하고 npm run dev
로 개발 서버를 실행하면 localhost:3000/sample
이라는 URL로 접근할 수 있다.
function sample() {
return (
<div>sample 페이지 입니다.</div>
)
}
export default sample
- 파일 내부에서 컴포넌트 위에 구현하는 함수나 해당 함수의 반환 값에 따라 렌더링 방법이 달라지는데, 각 페이지들이 어떤 타입으로 설정돼 있는지 빌드시 결과로 확인할 수 있다.
- 빌드 결과에서 Server 가 SSR을, Static과 SSG가 SSG를, ISR이 ISR를 나타낸다.
- CSR은 모든 페이지 타입과 함께 사용할 수 있으며 기본적으로는 이 타입들에 포함돼 있으므로 빌드 결과에는 표시되지 않는다.
npm run build
Next.js의 페이지와 페이지 취득
- Next.js 에서는 구현하는 함수나 해당 함수의 반환 값에 따라, pages의 렌더링 방법이 달라짐.
- 렌더링 방법을 결정하는 주요한 요소는 데이터 취득 함수
종류 | 데이터 취득에 사용하는 주요 함수 | 데이트 취득 시점 | |
---|
SSG | getStaticProps | 빌드 시(SSG) | 데이터 취득을 전혀 수행하지 않는 경우도 SSG에 해당 |
SSR | getServerSideProps | 사용자 요청 시(서버 사이드) | getInitialProps를 사용해도 SSR |
ISR | revalidate를 반환하는 getStaticProps | 빌드 시(ISR) | ISR은 배포 후에도 백그라운드 빌드가 실행된다. |
CSR | 그 밖의 임의의 함수(useSWR 등) | 사용자 요청 시(브라우저) | CSR은 SSG/SSR/ISR 과 동시에 사용 가능 |
- pages는 그 종류에 따라 데이터 취득에 사용할 수 있는 함수가 다름
- 페이지 컴포넌트에서 모든 표시 부분을 구현할 필요는 없음.
- 페이지 사이에서 공통으로 사용하는 코드나 UI 부분은 pages 디렉터리 밖에서 정의하고 임포트 해서 사용할 수 있음.
SSG를 통한 페이지 구현
- pages 아래에 새롭게 ssg.tsx 라는 이름의 파일을 추가하고, 페이지 컴포넌트를 구현해보자.
NextPage
는 pages를 위한 타입
- 받을 props를 결정하고,
NextPage<Props>
와 같이 지정
import { NextPage } from 'next'
import Head from 'next/head'
type SSGProps = {}
const SSG: NextPage<SSGProps> = () => {
return (
<div>
{}
<title>Static Site Generation</title>
<link rel="icon" href="/favicon.io" />
<main>
<p>
이 페이지는 정적 사이트 생성을 통해 빌드 시 생성된 페이지입니다.
</p>
</main>
</div>
)
}
export default SSG
npm run build
로 빌드를 실행하고, npm run dev
실행시 브라우저에서 http://localhost:3000/ssg
에 접속하면 구현한 페이지가 표시됨을 확인할 수 있음.
getStaticProps를 사용한 SSG를 통한 페이지 구현
- 파일 안에
getStaticProps
라는 함수를 정의하고 익스포트하면, 해당 함수는 빌드 시 실행된다.
getStaticProps
는 반환값으로 props를 반환할 수 있으며, 그 값이 페이지 컴포넌트에 전달되어 그려진다.
pages/ssg.tsx
에 getStaticProps
를 추가하고, 다시 빌드해보자.
import { GetStaticProps, NextPage, NextPageContext } from 'next'
import Head from 'next/head'
type SSGProps = {
message: string;
}
const SSG: NextPage<SSGProps> = (props) => {
const { message } = props;
return (
<div>
{}
<title>Static Site Generation</title>
<link rel="icon" href="/favicon.io" />
<main>
<p>이 페이지는 정적 사이트 생성을 통해 빌드 시 생성된 페이지입니다.</p>
<p>{message}</p>
</main>
</div>
);
};
export const getStaticProps: GetStaticProps<SSGProps> = async (context) => {
const timestamp = new Date().toLocaleString();
const message = `${timestamp}에 getStaticProps가 실행됐습니다.`;
console.log(message);
return {
props: {
message,
},
};
};
export default SSG
npm run build
를 실행하면 getStaticProps
안에 있는 console.log
가 빌드 도중 실행되는 것을 확인할 수 있다.
npm run start
실행해서, 페이지를 표시하면 getStaticProps
에서 반환한 props를 사용해 페이지를 표시하고 있는 것을 확인할 수 있다.
npm run dev
를 사용해 개발 서버를 실행하는 경우에는 최신 코드를 사용해 페이지를 표시하기 때문에, 요청이 있을 때마다 getStaticProps
가 실행되고 서버에서 페이지를 생성
getStaticProps
는 익스포트(export)해야 하며, 비동기 함수로서 async와 함께 정의해야함
getStaticProps
의 인수에는 context
가 부여된다.
context
에는 빌드 시에 함께 사용할 수 있는 데이터가 포함되어 있다.
export async function getStaticProps(context) {
return {
props: {}
}
}
context
는 실행 관련 정보가 모인 객체로, context.locale
과 같은 형태로 접근가능하다.
파라미터 | 내용 |
---|
params | 경로 파라미터, SSG의 경우에는 getStaticPaths 함수를 별도로 정의했을 때 참조 가능 |
locale | 현재 로케일 정보(가능한 경우) |
locales | 지원하는 로케일 배열(가능하는 경우) |
preview | Preview Mode 여부 |
previewData | Preview Mode에서 setPreviewData에 따라 설정된 데이터 |
getStaticPaths를 사용한 여러 페이지의 SSG
- 이번에는 사용자 프로필이나 게시글 페이지 등 표시하는 데이터만 다른 페이지를 만들어보자.
- Next.js 의 동적 라우팅(Dynamic Routing) 기능을 사용하면 된다.
- 동적 라우팅은 다음 2가지 요소로 구성된다.
[파라미터].tsx
와 같이 []
로 감싼 특별한 파일명
getStaticProps
에 맞춰 getStaticPaths
를 사용한다.
getStaticPaths
getStaticProps
실행 전에 호출되는 함수로, 생성할 페이지의 경로 파라미터 조합(paths)과 폴백(fallback)을 반환한다.
paths
는 경로 파라미터의 조합을 나타내며, 배열의 각 요소가 1개의 페이지에 대응한다.
fallback
은 getStaticPaths
가 생성하는 페이지가 존재하지 않는 경우의 처리를 기술한다.
export async function getStaticPaths() {
return {
paths: [
{ params: { ... } }
],
fallback: false
}
}
pages/posts
디렉터리를 새롭게 만들고, [id].tsx
(pages/posts/[id].tsx
) 라는 파일을 만든다.
- 대괄호로 감싼 부분이 경로 파라미터를 나타낸다.
import { GetStaticPaths, GetStaticProps, NextPage } from "next";
import Head from 'next/head';
import { useRouter } from "next/router";
import { ParsedUrlQuery } from "querystring";
type PostProps = {
id: string;
}
const Post: NextPage<PostProps> = (props) => {
const {id} = props
const router = useRouter()
if (router.isFallback) {
return <div>Loading...</div>
}
return (
<div>
<Head>
<title>Create Next app</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<p>이 페이지는 정적 사이트 생성을 통해 빌드 시 생성된 페이지입니다.</p>
<p>{`/post/${id}에 대응하는 페이지입니다.`}</p>
</main>
</div>
)
}
export const getStaticPaths: GetStaticPaths = async () => {
const paths = [
{
params : {
id: '1',
},
},
{
params : {
id: '2',
},
},
{
params : {
id: '3',
},
},
]
return {paths, fallback: false}
}
interface PostParams extends ParsedUrlQuery {
id: string
}
export const getStaticProps: GetStaticProps<PostProps, PostParams> = async (context) => {
return {
props: {
id: context.params!['id'],
}
}
}
export default Post
getStaticPaths
에서는 id가 각각 1, 2, 3 인 경로 파라미터를 반환하고 /posts/1
, /posts/2
, /posts/3
의 3개 경로의 페이지를 생성한다.
- 여로 경로 파라미터를 사용하는 경우,
paths
의 각 요소에 추가 파라미터를 더할 수 있다.
paths
의 각 요소에 대해 getStaticProps
가 호출되고, 페이지가 생성된다.
getStaticProps
에는 context
인 params
로부터 경로 파라미터를 참조할 수 있다.
getStaticPaths
의 fallback
을 false
로 반환하면 paths
에 주어지지 않은 경로에 대해서는 404 페이지를 표시한다.
fallback
에 true
를 지정하면, 최초 요청과 그 뒤의 요청에서 작동이 달라진다.
- 우선, 가장 첫 번째 방문한 사용자에 대해서는 폴백 페이지를 처음에 표시한다.
- 이것은 페이지 컴포넌트의
props
가 빈 상태로 화면이 그려진 페이지이다.
- 서버 사이드에서는 요청의 경로에 대해
getStaticProps
를 실행한다. getStaticProps
가 반환한 props
는 페이지를 표시하고 있는 클라이언트에 전송되고 화면을 그린다.
- 또한 서버 사이드에서 props를 기반으로 페이지를 그리고 그 결과를 저장한다.
- 그 뒤, 동일한 경로에 대한 요청이 오면 저장했던 페이지를 반환한다.
SSR을 통한 페이지 구현
- SSR에서는 접근할 때마다 서버에서 페이지를 그리고, 그 결과를 클라이언트에서 표시한다.
- SSG의
getStaticProps
에 대해, SSR에서는 getServerSideProps
를 정의한다.
- SSR에서는 페이지를 그리기 전에
getServerSideProps
를 호출하며, 이 함수가 반환한 props 를 기반으로 페이지를 그린다.
pages/ssr.tsx
를 새롭게 작성하고, 다음 코드를 추가해보자.
import { GetServerSideProps, NextPage } from "next";
import Head from 'next/head';
type SSRProps = {
message: string
}
const SSR: NextPage<SSRProps> = (props) => {
const {message} = props
return (
<div>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<p>이 페이지는 서버 사이드 렌더링을 통해 접근 시에 서버에서 그려진 페이지 입니다.</p>
<p>{message}</p>
</main>
</div>
)
}
export const getServerSideProps: GetServerSideProps<SSRProps> = async (
context
) => {
const timestamp = new Date().toLocaleDateString()
const message = `${timestamp}에 이 페이지의 getServerSideProps가 실행됐습니다.`
console.log(message)
return {
props: {
message,
}
}
}
export default SSR
- 접근할 때마다 표시되는 내용이 변하기 때문에, 매번 서버에서 getServerSideProps가 호출되고 페이지가 그려지는 것을 알 수 있다.
getServerSideProps
의 인수인 context
에는 getStaticProps
의 context
에서 참조할 수 있는 데이터와 함께 요청 정보들을 참조할 수 있다.
파라미터 | 내용 |
---|
req | http.IncomingMessage의 인스턴스에서 요청 정보나 쿠키(Cookie)를 참조할 수 있다. |
res | http.ServerResponse의 인스턴스에서 쿠키를 설정하거나, 응답 헤더를 치환할 때 사용할 수 있다. |
resolveUrl | 실제로 접근이 있던 경로 |
query | 해당 쿼리를 객체로 만든 것 |
ISR을 통한 페이지 구현
- 점진적 재생성(ISR)은 SSG의 응용이라 말할 수 있는 렌더링 방법
- 특징으로 페이지 수명을 정할 수 있으며, 수명을 지난 페이지에 대해서는 최신 정보로 재생성을 시도하고, 정적 페이지를 전송하면서 정보를 업데이트할 수 있다.
- ISR에는
revalidate
를 반환하는 getStaticProps
를 사용한다. getStaticProps
에서 revalidate
를 반환하면 그 값이 유효 기간이 되며, 유효 기간이 지난 페이지는 재생성된다.
- 다음 코드는 ISR을 사용한 예이다. (
pages/isr.tsx
)
getStaticProps
를 정의하고, getStaticProps
에서는 props
와 함께 revalidate
를 반환한다.
revalidate
는 페이지의 유효 기간을 초로 나타낸 것을 반환한다.
import { GetStaticPaths, NextPage, GetStaticProps } from "next";
import Head from 'next/head'
import {useRouter} from 'next/router'
type ISRProps = {
message: string
}
const ISR: NextPage<ISRProps> = (props) => {
const {message} = props
const router = useRouter()
if (router.isFallback) {
return <div>Loading...</div>
}
return (
<div>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<p>이 페이지는 ISR을 통해 빌드 시 생성된 페이지입니다.</p>
<p>{message}</p>
</main>
</div>
)
}
export const getStaticProps: GetStaticProps<ISRProps> = async (context) => {
const timestamp = new Date
const message = `${timestamp}에 이 페이지의 getStaticProps가 실행됐습니다.`
return {
props : {
message,
},
revalidate: 60
}
}
export default ISR
- 가장 처음으로 페이지에 접근한 경우에는 SSG와 마찬가지로 폴백 페이지가 표시되고, 서버 측에서 실행한
getStaticProps
를 기반으로 클라이언트에서 다시 화면을 그린다.
- 그 이후의 요청에 대해서는
revalidate
에서 지정한 시간 내에서는 서버 사이드에서 그려서 저장하고 있던 페이지(같은 페이지)를 반환한다.
- 유효 기간이 지난 뒤 요청이 있는 경우에는, 해당 요청에 대해서는 현재 저자오대 있는 페이지를 반환한다.
- 그리고
getStaticProps
를 실행하고 페이지를 그려 새로운 캐시로 저장한다.