개요
생각해보면 현재 재직중인 회사에서 관리자 페이지를 제외한 프론트 서비스들은 모두 Next.js 를 사용하고 있는데
Next.js 프레임워크를 시간들여 공부해본 적이 따로 없는 것 같다. 🥲
핑계를 대보자면 React.js 만 사용할 줄 알아도 Next.js 으로도 그냥저냥 개발이 가능하기 때문이었다.
게을렀던 본인을 속죄하는 마음으로 Next.js 를 사용하며 의문이 들었던 부분들 위주로 하나씩 공부해나가보고자 한다.
data fetching 메서드들을 정리하는 것으로 첫 글을 시작해본다.
Pre-Rendering
Next.js 는 페이지 요청시 자체적으로 pre-render 한 html 파일을 응답하고, 브라우저에서 hydration 위해 필요한 코드를 재호출하는 방식을 사용하고 있다. 이로써 빠른 초기 로드 속도와 SEO 를 제공한다.
이때 Next.js 에서는 pre-render를 위한 방법으로,
- Static Generation
- Server Side Rendering
두가지 방식을 제공한다.
두 방식은 한 프로젝트 내에서 혼용되어 사용될 수 있다.
때문에 페이지를 새로 추가하게 될때, 페이지 특성에 따라 어떤 방식으로 pre-render를 해야할지 선택할 수 있어야 한다.
Static Generation
SG 방식은 프로젝트 build 시에 data fetching 메서드를 호출하는 방식이다. 따라서 해당 메서드로 pre-render된 페이지는 정적이며, cdn 에 캐시될 수 있기에 더 빠른 퍼포먼스를 제공한다. 더 나은 퍼포먼스를 제공하기에 권장되는 방법이다.
이때, 생성되는 정적 페이지에 외부 데이터들도 포함시킬 수 있는데 이는 client-side data fetching 통해 외부 데이터도 포함시킬 수 있다는 뜻이다.
- 빌드시에 페이지를 생성. 미리 생성해둔 페이지를 호출하기에 더 빠른 퍼포먼스 제공
- client-side data fetching 을 통해 외부 데이터들도 포함 가능
getStaticProps
getStaticProps는 pre-render될 컴포넌트에 props로 데이터를 전달하는 방식이다.
하지만 위 함수는 빌드 시점을 기준으로 호출된 함수이기 때문에 빌드 이후에도 빈번히 응답값이 바뀌는 api를 pre-fetch하기에는 부적합하다.
function Blog({ posts }) {
// Render posts...
}
// This function gets called at build time
export async function getStaticProps() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
export default Blog
getStaticPaths
Next.js는 변수가 포함된 경로를 생성할 수 있다.
/posts/[id].js
getStaticPaths는 이러한 동적인 url에 포함되는 데이터를 결정해준다.
// This function gets called at build time
export async function getStaticPaths() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}
getStaticPaths는 getStaticProps와 함께 쓰일 수 있으며 다음과 같이 getStaticPaths 에서 결정된 path를 getStaticProps에서 사용할 수 있다.
function Post({ post }) {
// Render post...
}
export async function getStaticPaths() {
// ...
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return { props: { post } }
}
export default Post
Server-side Rendering
SSR 을 사용하는 페이지는 매 요청시마다 page HTML 이 생성된다. 그러기에 SSR 에서 data fetch의 결과가 빈번히 바뀌는 경우에 적합하다.
getServersideProps
사용 및 동작은 getStaticProps와 매우 유사하다. 다만 호출될 때가 빌드 시점인지, 페이지 요청 시점인지가 다를 뿐이다.
function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default Page
getInitialProps (주의)
공식문서에서 더이상 권장하지 않는 방법이다. 다만 왜 권장하지 않고 어떤 차이가 있는지 알아둘 필요는 있다.
getServersideProps와 마찬가지로 페이지 요청때마다 함수가 호출된다.
function Page({ stars }) {
return <div>Next stars: {stars}</div>
}
Page.getInitialProps = async (ctx) => {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const json = await res.json()
return { stars: json.stargazers_count }
}
export default Page
다만 위 함수가 어떻게 호출되는지 살펴보자.
Page.getInitialProps = async (ctx) => { ... }
export 되는 getServersideProps 와 다르게 페이지 컴포넌트 내의 멤버 함수를 호출하는 형식이다.
Next.js는 pre-render 가 된 페이지를 먼저 브라우저에 응답하여 빠른 초기 로드를 제공하는데 이때 멤버 함수인 getInitialProps 코드도 함께 브라우저에 내려가게 된다. 단순히 코드가 함께 내려가는게 무슨 문제가 될 수 있느냐 할 수 있지만, getInitialProps에서 외부 모듈을 사용하고 있다면 외부 모듈도 함께 브라우저에 응답되기 때문에 응답 시간이 길어져 문제가 될 수 있는 것이다. 이러한 side-effect 때문에 Next.js 에서는 더이상 getIntialProps를 권장하지 않는다.
다만 getIntialProps의 내용이 브라우저로 함께 응답되기 때문에 이로 인한 이점도 있다. Next.js 에서 next/link, next/router 따위로 client-side navigation을 구현할 수 있다. 이때 getInitialProps는 이미 브라우저에 있는 코드이기에 별도로 server로 요청하지 않고 브라우저에서 data fetch를 할 수 있기에 서버 부담을 줄일 수 있다.
이 내용과 관련된 github discussion 이 있다. https://github.com/vercel/next.js/discussions/11211
정리
Pre-render on Next.js
- 목적
- 빠른 초기 로드 속도
- SEO
- 방식
- sever-side data fetching
- 브라우저에게 html pre-render request
- 브라우저에서 hydration을 위한 코드 재요청
API
- Static Generation
- Data Fetch 시점: 빌드시
- Method: getStaticProps, getStaticPaths
- Sever-side Rendering
- Data Fetch 시점: 페이지 요청시
- Method: getServersideProps, getInitialProps
참고
https://nextjs.org/docs/basic-features/pages
https://nextjs.org/docs/api-reference/data-fetching/get-initial-props
'Study' 카테고리의 다른 글
OpenSource Contribute 후기 (2) | 2023.11.20 |
---|---|
웹 요청 중단 시키기 (ft. AbortController) (0) | 2022.08.15 |