
이번에는 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초 이상 지난 후 반복되면 오래된 응답이 전혀 사용되지 않으며 브라우저의 요청을 이행하고 캐시 재검증이 모두 네트워크에서 응답을 받는 데 달려 있다.
