Docs_Data Fethcing(SSG-getStaticProps)
getStaticProps
만약 getStaticProps를 사용하면 *build time때 getStaticProps에 의해 받아진 props를 이용하여 pre-render된다.
build time이란 'next build'명령어로 배포할때의 배포프로세스과정을 의미한다.
이는 getStaticProps를 활용함에 있어서 굉장히 중요한 개념이다.
결론적으로 revalidate함수를 통해 옵션을 따로 지정하지 않는 한 getStaticProps에 의한 데이터는 오직 배포하는 단계에서만 머무른다. revalidate함수를 통해 옵션을 따로 지정하지 않는 한 절대 업데이트되지 않는다.
export async function getStaticProps(context) {
return {
props: {}, // 페이지에 있는 컴포넌트에 props로 넘겨진다.
}
}
⚠️Caution
어떤 렌더링타입과도 관계없이 모든 props는 페이지 컴포넌트로 전달되며 초기에 Next에 의해 빌드된 HTML 즉, 클라이언트 측에서 볼 수 있다. 이는 올바른 *hydrate를 위해 필요하다. 그렇기에 props에 전달되는 정보가 민감한 정보가 함부로 전달되지 않도록 주의해야한다.
1. SSR, SSG, CSR이든 관계없이 모든 props에 해당한다.
2. hydrate: https://programmerkokkiri.tistory.com/232
when should I use getStaticProps
- 페이지를 렌더해야하는 데이터가 유저가 요청과 관계없이 이미 필요한 데이터일 경우
- SEO를 위해 페이지가 pre-render되야하고, 빠른 로드속도를 원할경우 -> getStaticProps는 HTML과
JSON파일을 만들어내는데, 그 두개모두 성능을 위해 CDN에 의한 cached가 가능하다. - 데이터가 *headless CMS로부터 받아지는 경우
- 데이터가 민감한 정보를 포함하지 않아(not user-specific) 공공적으로 cached되는 상황사용할 수 있는데, 이경우 경로를 재작성하는 Middleware를 사용하면서 우회할 수 있다고 한다.
pre-render가 필요한 상황예시
1. SEO: 검색 엔진은 HTML 파일을 크롤링하여 웹 페이지를 검색 결과에 노출한다. SSR을 적용하지 않는 경우, 검색 엔진은 페이지의 초기 로딩 시점에는 빈 페이지를 읽어들일 수 있다. 이러한 경우 검색 엔진 최적화를 위해 프리 랜더링이 필요하다.
2. 초기 로딩 속도 개선: CSR은 초기 로딩 시간이 길어지는 단점이 있다. 이는 CSR이 모든 컴포넌트를 클라이언트에서 로드한 후 렌더링하기 때문이다. 이에 반해, 프리 랜더링은 초기 로딩 시간을 줄여 성능을 향상시킬 수 있다.
3. 모바일기기 최적화: 모바일기기는 CPU나 메모리 등의 성능이 PC보다 낮기 때문에 CSR의 초기 로딩 속도 문제가 더 크다. 프리 랜더링을 적용하면 모바일 기기에서의 성능을 개선할 수 있다.
4. 보안이슈: CSR은 클라이언트 측에서 코드를 실행하므로 보안상의 문제가 발생할 수 있다. 이러한 경우 프리 랜더링을 적용하여 보안을 강화할 수 있다.
headless CMS란?
CMS는 컨텐츠를 관리하는 시스템을 의미하고, 헤드리스 CMS는 콘텐츠를 생성/저장/관리하는 콘텐츠 관리 시스템만 제공하고 사용자들에게 콘텐츠가 보이는 부분은 API로 따로 제공하는 시스템을 말한다. 이때 보여지는 것(view)은 단순히 테마나 스킨을 말한다기 보다 디바이스나 다양한 환경에 대응하는 보다 확장되는 개념인 것 같다. 이렇게 컨텐츠 관리 도구와 보여주는 시스템 분리시킨 이유는 컨텐츠를 여러 상황에 맞게 재사용하기 쉽고 새롭게 되입되는 기술을 접목하기 쉽게하기 위해서이다.
when does getStaticProps run
getStaticProps는 클라이언트측에서 작동하는경우가 절대 없으며, 오직 서버측에서만 작동한다.
클라이언트측에 bundle되면서 지워진(아마 물리적으로 코드가 삭제된게 아니라, 보여주지만 않는 코드는 다음 next에서 제공하는 tool을
이용해 확인할 수 있다.) -> https://next-code-elimination.vercel.app/
next-transpile-modules 라이브러리를 사용하면 유저측에게 bundle되는 코드내역을 따로 확인할 수 있다.
- getStaticProps는 항상 next build타임때만 작동한다. -> 배포하는 과정에서만 작동한다는 의미. 배포되고나서는 작동x
(아래에 언급하는 revalidate함수를 이용해 다시 작동가능하게 할 수 있음.) - [fallback: true]옵션을 사용하면 *background에서 작동할 수 있다.
- revalidate옵션을 사용할경우에도 항상 background에서 작동한다.
- revalidate()함수를 사용할 경우에는 따로 호출할때에만(정해진 시간이 되었을때) background에서 작동한다.
- [fallback: blocking]옵션을 사용하면 initial render이전에 getStaticProps가 호출된다.
이때 background환경이란 것은 사용자가 페이지를 요청하는 시점이 아니라 Next.js가 페이지를 다시 생성하는 시점에 실행된다는 것을 의미한다. 즉,getStaticProps함수가 실행되는 동안에도 사용자는 다른 페이지를 볼 수 있다. 사용자가 요청하는 페이지가 다시 생성될 때까지 기존 페이지가 보여지는 것인데, 이러한 방식으로revalidate 옵션을 사용하면, 최신 데이터를 보여주면서도 서버 부하를 줄일 수 있다.
getStaticProps는 정적인 HTML페이지를 만들어내는 함수이다보니, request에 대한 동적인 정보(query parameters, HTTP headers)를 제공할 수 없다. 만약 이러한 정보를 제공해야하는경우 Middleware를 함께 사용해야 한다.
예를들어, Middleware는 HTTP 요청처리과정의 중간에서 실행된다. 이를 통해, 요청과 관련된 정보를 처리하고, getStaticProps 함수에 전달할 수 있다. 즉, 요청 헤더 정보가 필요한 경우, 미들웨어를 통해 해결(동적정보를 getStaticProps함수에 전달)할 수 있다.
Using getStaticProps to fetch data from a CMS
다음코드의 CMS로부터 블로그포스트목록을 받아오는 예제이다.
// posts will be populated at build time by getStaticProps()
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries.
export async function getStaticProps() {
// Call an external API endpoint to get posts.
// You can use any data fetching library
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
Write server-side code directly
위에서 언급했듯, getStaticProps는 클라이언트측에서 작동하는경우는 절대 없으며, 오직 서버측에서만 작동한다. 이는 심지어 브라우저에게 제공되는 JS bundle파일에도 포함되어있지 않다.
즉, getStaticProps를 사용하여 데이터베이스 쿼리를 직접적으로 작성할 수 있는데, 이렇게 작성한 쿼리는 서버사이드에서만 실행되기 때문에, 보안상의 이유로 민감한 데이터에 대한 액세스를 허용하는 경우에도 안전하게 사용할 수 있다.
getStaticProps코드 내에서 API route를 직접 호출하여 바로 데이터를 가져오려고 시도한다면, 추가적인 호출을 야기하고, 이는 성능저하를 일으킨다. 그렇게 작성하는 대신 lib/폴더내에 있는 로직을 getStaticProps내에 작성하여 호출하는 것이 더 효율적이다.
쉽게 말하자면, getStaticProps 함수 내에서 API를 호출하는 경우, 매 요청마다 API를 호출하여 데이터를 가져와야 하므로, 요청이 많아질수록 성능 저하가 발생하는 것이고. lib/ 디렉토리를 사용하는 경우, 데이터를 미리 가져와서 공유하므로 요청 수와는 무관하게 일정한 성능을 유지할 수 있다는 것이다.
// 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 } }
}
- fetch()함수는 getStaticProps내에서 직접 사용할 수 있다. 이는 fetch함수는 클라이언트 측에서 실행되므로 필요한 경우에만(유저가 요청한 경우에만) 실행되기때문
Statically generates both HTML and JSON
getStaticProps를 사용하는 페이지가 빌드타임때 pre-render되면 HTML파일뿐 아니라 getStaticProps에 의한 JSON 파일도 생성한다. 생성된 JSON 파일은 client-side routing(next/link or next/router)을 하는데 사용된다.
만약 유저가 getStaticProps를 사용해 pre-rendered된 페이지로 이동하면 Next.js는 빌드타임때 미리 생성해놓은 JSON 파일을 받아온다. 그리고 페이지컴포넌트를 위해 사용한다. 그니까 다시말하자면, JSON파일은 빌드타임때 생성되니까 클라이언트측에서 페이지 이동을 할때에는 getStaticProps함수가 실행되지 않는다는 의미이다.
Incremental Static Generation을 사용할때에는 getStaticProps가 유저가 페이지를 이동할때 background에서 JSON파일을 생성해낸다. 여려 request를 보내는것처럼 보이는데, 이건 의도된 것이고 결론적으로는 성능에 큰 영향을 안미치니까 걱정하지 않아도 된다.
Where can I use getStaticProps
getStaticProps는 페이지-컴포넌트에서만 export될 수 있다. 만약 페이지가 아닌, _app, _documnet 혹은 _error와 같은 곳에서는 export할 수 없다. 이러한 제한의 이유는 react는 페이지가 렌더되기 이전에 데이터를 받아오기를 원하기 때문이다.
또한 getStaticProps 내보내기를 독립적으로 사용해야 한다. getStaticProps를 페이지 구성 요소의 속성으로 추가하면 작동하지 않는다.
function MyPage({ data }) {
export async function getStaticProps() {
const res = await fetch('https://example.com/data');
const data = await res.json();
return {
props: {
data
}
};
}
}
export default MyPage;
Runs on every request in development
개발모드에서는 (next dev) getStaticProps가 빌드타임때만 HTML파일과 JSON파일을 생성하는 것이 아니라, 요청마다 return한다.
preview Mode
preview mode에서는 빌드타임때 pre-render된 페이지를 렌더하는것이 아니라 request time에 맞춰 렌더된 페이지를 볼 수 있다.