-
Next.js - SSG, getStaticPropsReact.js & Next.js 2022. 9. 18. 20:39
Data Fetching: getStaticProps | Next.js
정의
getStaticProps 메서드를 export 한다면, Next.js 는 getStaticProps 에 의해 반환되는 props를 빌드 타입에 프리-렌더할 것입니다.
export async function getStaticProps(context) { return { props: {}, // will be passed to the page component as props } }
언제 getStaticProps를 사용할까?
우리는 이런 상황에서 getStaticProps 를 사용할 수 있습니다 :
- The data required to render the page is available at build time ahead of a user’s request
- The data comes from a headless CMS
- The page must be pre-rendered (for SEO) and be very fast —
getStaticProps
generatesHTML
andJSON
files, both of which can be cached by a CDN for performance - The data can be publicly cached (not user-specific). This condition can be bypassed in certain specific situation by using a Middleware to rewrite the path.
- 빌드시 고정되는 값으로 빌드 이후에는 수정이 불가능합니다
- data를 빌드 시에 미리 땡겨와 정적으로(static 하게) 제공합니다
- 매 유저의 요청마다 fetch할 필요가 없는 데이터를 가진 페이지를 렌더링할 때 유리합니다
- 유저에 구애받지 않고 퍼블릭하게 캐시할 수 있는 데이터
- SEO 등의 이슈로 인해 빠르게 미리 렌더링해야만 하는 페이지
언제 getStaticProps 메서드가 실행될까?
getStaticProps 메서드는 오직 서버에서 동작하며 클라이언트 단에서 동작하지 않습니다. getStaticProps 메서드 내부에 validate 코드를 추가하여, client-side 에서 번들링되는 것을 제거할 수 있습니다.
getStaticProps
always runs duringnext build
getStaticProps
runs in the background when using[fallback: true](https://nextjs.org/docs/api-reference/data-fetching/get-static-paths#fallback-true)
getStaticProps
is called before initial render when using[fallback: blocking](https://nextjs.org/docs/api-reference/data-fetching/get-static-paths#fallback-blocking)
getStaticProps
runs in the background when usingrevalidate
getStaticProps
runs on-demand in the background when using[revalidate()](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration#on-demand-revalidation)
어디서 getStaticProps를 사용할 수 있을까?
getStaticProps 는 오직 페이지에서만 exported될 수 있습니다.
_app
,_document
, or_error
과 같은 페이지에서는 사용할 수 없습니다. 이것 들이 제한되는 이유들 중 하나는 리액트는 페이지가 렌더링되기 전에 모든 데이터를 필요로 하기 때문입니다.CMS로 부터 데이터를 패칭하기위해 getStaticProps 사용하기
// 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
SSG 적용하기 예시
사용할 디렉터리 구조는 다음과 같습니다
- pages - movie - spiderman - index.tsx 🔥 - [name].tsx - index.tsx - next.config.js
spiderman/index.tsx
이전 SSR 사용 시에는 build 된 정적 파일을 가지고 있는 것이 아닌, 매 요청 마다 정보를 가져오는 흐름이었습니다. 이번에는 이런 구조에서 spiderman 이라는 정적 파일을 가지고 있다는 것을 가정합니다.
export async function getStaticProps() { const res = await fetch( `https://api.themoviedb.org/3/search/movie?api_key=${REACT_APP_API_KEY}&language=en-US&query=spiderman` ); const data: Imovie = await res.json(); return { props: { data } }; }
구조는 위에 설명한 구조와 같습니다. fetch 함수를 통해 api 요청을 보내고 해당 데이터가 온전히 전달되었다면, json으로 반환하여 props로 반환합니다.
사용한 API 는 영화 데이터를 무료로 제공하는 사이트인 TMDB 입니다. 실제로 따라하고 싶은 경우 해당 사이트에 회원가입 이후 키 값을 넣어주세요. 우리가 봐야할 부분은 쿼리 부분입니다.
&query=spiderman
이전 SSR 을 사용할 때는 query 문에 context.params 내부에 있는 다이나믹 라우팅 경로 값을 넣어주었었습니다.
&query=${context.params?.name}
하지만 이번에는 빌드 시에 해당 요청에 대한 데이터를 가지고 있어야 하기 때문에 query 문에 원하는 값(spiderman) 을 직접 입력해줍니다.
반환된 리턴 값을 받아 렌더링하는 부분은 다음과 같습니다.
interface ISpiderMan { data: Imovie; } const SpiderMan = ({ data }: ISpiderMan) => { const { results } = data; return ( <> <div> <h1>Hello Movie</h1> <div style={{ display: 'flex', flexWrap: 'wrap' }}> {results.map((movie) => ( <div style={{ marginTop: 5, display: 'flex', marginRight: 10 }} key={movie.id}> <div style={{ position: 'relative', color: 'white' }}> <Image width={250} height={200} src={ movie.backdrop_path ? `https://image.tmdb.org/t/p/original/${movie.backdrop_path}` : `https://freesvg.org/img/1645699345cat.png` } alt={movie.title} /> <span style={{ position: 'absolute', top: 5, right: 5, textShadow: '#000 1px 0 10px', }} > {movie.title} </span> </div> </div> ))} </div> </div> <button type='button' onClick={() => (location.href = `/movie_SP`)}> back to main </button> </> ); }; export default SpiderMan;
이전 SSR 에 사용된 [name].tsx 와 구조가 동일한 것을 알 수 있습니다.
이렇게 SSG 를 사용하면 우리가 HTML 로 클라이언트 단에서 하드코딩할 데이터를 직접 가지고 있을 필요가 없기 때문에 클라이언트 단의 부담이 덜어지게 됩니다. 또한 서버-사이드에서 HTML 파일 및 데이터를 정적으로 가지고 있기 때문에 SEO에도 유리합니다.
전체 코드 보기
// types/movie/index.ts interface ImovieResults { adult: boolean; backdrop_path: string; genre_ids: string[]; id: number; original_language: string; original_title: string; overview: string; popularity: number; poster_path: string; release_date: string; title: string; video: boolean; vote_average: number; vote_count: number; } export interface Imovie { page: number; results: ImovieResults[]; total_pages: number; total_results: number; }
import Image from 'next/image'; import { REACT_APP_API_KEY } from 'config'; import { Imovie } from '@/types/movie'; interface ISpiderMan { data: Imovie; } const SpiderMan = ({ data }: ISpiderMan) => { const { results } = data; return ( <> <div> <h1>Hello Movie</h1> <div style={{ display: 'flex', flexWrap: 'wrap' }}> {results.map((movie) => ( <div style={{ marginTop: 5, display: 'flex', marginRight: 10 }} key={movie.id}> <div style={{ position: 'relative', color: 'white' }}> <Image width={250} height={200} src={ movie.backdrop_path ? `https://image.tmdb.org/t/p/original/${movie.backdrop_path}` : `https://freesvg.org/img/1645699345cat.png` } alt={movie.title} /> <span style={{ position: 'absolute', top: 5, right: 5, textShadow: '#000 1px 0 10px', }} > {movie.title} </span> </div> </div> ))} </div> </div> <button type='button' onClick={() => (location.href = `/movie_SP`)}> back to main </button> </> ); }; export default SpiderMan; export async function getStaticProps() { const res = await fetch( `https://api.themoviedb.org/3/search/movie?api_key=${REACT_APP_API_KEY}&language=en-US&query=spiderman` ); const data: Imovie = await res.json(); return { props: { data } }; }
'React.js & Next.js' 카테고리의 다른 글
Next.js - 스타일드 컴포넌트에 SSR 적용하기 (0) 2022.09.25 Next.js - CSR, Client side data fetching (0) 2022.09.18 Next.js - SSR, getServerSideProps 적용하기 (0) 2022.09.18 Next.js - 초기화 이후 기본 구조 설정하기 (0) 2022.09.18 리액트에서 다수의 체크 박스 다루기 (0) 2022.09.13