이번에는 Next.js에서 설명하는 Data Fetching을 주제로 작성해보려 한다.
Data fetching에 따라 Next.js는 서로 다른 랜더링을 제공한다.
getStaticProps
함수를 페이지에서 사용하면 이 페이지는 Static Site Generation으로 렌더링 한다. 이는 빌드 타임에 props를 사용해 렌더링하게 된다.
import type { InferGetStaticPropsType, GetStaticProps } from 'next'
type Repo = {
name: string
stargazers_count: number
}
export const getStaticProps = (async (context) => {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const repo = await res.json()
return { props: { repo } }
}) satisfies GetStaticProps<{
repo: Repo
}>
export default function Page({
repo,
}: InferGetStaticPropsType<typeof getStaticProps>) {
return repo.stargazers_count
}
pre-rendering되는 방식과 관계없이 페이지 컴포넌트들에 어떠한 props든 통과되며, client-side HTML에서는 볼 수 있다. 그렇기에 민감한 정보는 props로 전달하면 안된다.
getStaticProps
는 항상 서버에서 실행되며 클라이언트에서는 실행되지 않는다.
next build
명령어를 실행 중에 항상 실행된다.fallback: true
옵션을 사용하면 background에서 실행된다.fallback: blocking
옵션을 사용하면 초기 랜더링 전에 실행된다.revalidate
옵션을 사용하면 background에서 실행된다.revalidate()
옵션을 사용하면 background에서 요청이 올때 실행된다.getStaticProps
는 서버에서만 실행되기 때문에 브라우저를 위한 js bundle에 포함되지 않는다. 그래서 db queries에 직접적으로 접근할 수 있다. getStaticProps
내에서 직접 서버사이드 코드를 작성할 수 있다.
// lib/load-posts.js
// The following function is shared
// with getStaticProps and API routes
// from a `lib/` directory
export async function loadPosts() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts/')
const data = await res.json()
return data
}
// pages/blog.js
import { loadPosts } from '../lib/load-posts'
// This function runs only on the server side
export async function getStaticProps() {
// Instead of fetching your `/api` route you can call the same
// function directly in `getStaticProps`
const posts = await loadPosts()
// Props returned will be passed to the page component
return { props: { posts } }
}
getStaticProps
는 빌드시 pre-rendering되면 HTML 파일 이외에도 json파일을 생성한다.
json파일은 클라이언트 측에서 routing시(next/link, next/router)에 사용된다. 페이지 에서는 props를 위해 이 json을 fetch하게 된다. 이는 클라이언트 측 페이지의 전환이 다시 getStaticProps
를 부르는 것이 아닌 한번 export된 json을 사용한다.
getStaticProps
는 페이지에서만 export할 수 있다. 페이지가 아닌 파일들(_app
,_document
,_error
)에서는 사용이 불가능하다.
그 이유는 react는 페이지가 렌더링 되기 전에 데이터가 필요하기 때문이다.
페이지들이 동적인 router를 가지고 있고 getStaticProps
를 사용한다면 정적으로 생성될 path들의 리스트 정의가 필요할 것이다.
getStaticPaths
에 정의된 내용에 따라 정적으로 pre-rendering을 진행할 것이다.
import type {
InferGetStaticPropsType,
GetStaticProps,
GetStaticPaths,
} from 'next'
type Repo = {
name: string
stargazers_count: number
}
export const getStaticPaths = (async () => {
return {
paths: [
{
params: {
name: 'next.js',
},
}, // See the "paths" section below
],
fallback: true, // false or "blocking"
}
}) satisfies GetStaticPaths
export const getStaticProps = (async (context) => {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const repo = await res.json()
return { props: { repo } }
}) satisfies GetStaticProps<{
repo: Repo
}>
export default function Page({
repo,
}: InferGetStaticPropsType<typeof getStaticProps>) {
return repo.stargazers_count
}
동적인 routes를 사용할 때와 더블어 아래와 같은 상황일떄 getStaticPaths
를 사용해야 한다.
getStaticPaths
는 production빌드일때만 실행되고 런타임에서는 실행되지 않는다.
getStaticPaths
에 따른 getStaticProps
실행 방식
fallback: true
옵션을 사용할 때 background에서 실행된다.fallback: blocking
옵션을 사용할 때 초기 랜더링 전에 실행된다.getStaticPaths
는 반드시 getStaticProps
와 함께 쓰여야 한다.getServerSideProps
와 같이 사용할 수 없다.getStaticPaths
는 페이지 구성 요소의 속성이 아닌 독립 실행형 함수로 내보내야 한다.getServerSideProps
를 사용하면 Server-side Rendering으로 인식해 매요청마다 pre-rendering을 진행한다.
import type { InferGetServerSidePropsType, GetServerSideProps } from 'next'
type Repo = {
name: string
stargazers_count: number
}
export const getServerSideProps = (async (context) => {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const repo = await res.json()
return { props: { repo } }
}) satisfies GetServerSideProps<{
repo: Repo
}>
export default function Page({
repo,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
return repo.stargazers_count
}
getServerSideProps
는 서버사이드에서만 실행되고 브라우저에서는 실행되지 않는다.
요청 시 데이터를 가져와야 하는 페이지를 렌더링해야 하는 경우에만 사용해야 한다. 만약 요청에 데이터를 렌더링할 필요가 없다면 client-side나 getStaticProps를 사용하는 것을 고려해야 한다
ssr에서 header를 통해 캐시를 사용할 수 있다.
// This value is considered fresh for ten seconds (s-maxage=10).
// If a request is repeated within the next 10 seconds, the previously
// cached value will still be fresh. If the request is repeated before 59 seconds,
// the cached value will be stale but still render (stale-while-revalidate=59).
//
// In the background, a revalidation request will be made to populate the cache
// with a fresh value. If you refresh the page, you will see the new value.
export async function getServerSideProps({ req, res }) {
res.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)
return {
props: {},
}
}
10초 동안은 신선한 값(fresh)이다. 10초에서 60초 사이에 요청이 반복되면 캐시된 값은 유효하지 않지만 API 요청을 이행하는 데 사용된다. 동시에 "백그라운드에서" 나중에 사용할 수 있도록 캐시를 새 값으로 채우기 위해 유효성 재확인 요청이 수행된다. 요청이 60초 이상 지난 후 반복되면 오래된 응답이 전혀 사용되지 않으며 브라우저의 요청을 이행하고 캐시 재검증이 모두 네트워크에서 응답을 받는 데 달려 있다.