-
next.js getInitialProps, getServerSideProps, getStaticProps, getStaticPath,Frontend/NextJS 2023. 5. 1. 15:47
여러 Next.js 프로젝트를 보다보면 흔하게 getInitialProps, getStaticPath, getStaticProps, getServerSideProps들을 마주하곤 한다. 이들의 역할을 쉽게 생각하면 React의 useEffect의 역할을 생각하면 쉽다.
React의 useEffect의 경우 렌더링 전 사전에 data를 fetching하기 위해 사용된다.
next에서도 이같은 기능을 getInitialProps, getStaticPath, getStaticProps, getServerSideProps를 통해 제공한다.
각각의 종류를 하나하나 자세히 살펴보자.
1. getInitialProps
이름에서 쉽게 유추할 수 있 듯, getInitialProps는 서버에서 실행되어 data를 미리 fetching한 상태로 렌더링할 때 사용할 수 있다. 이를 SSR의 장점인 SEO를 연관지어 추론해볼 수 있는데, 공식 docs에서는 SEO에 특히 유용하다라고 설명하고 있다.
이러한 특징으로 볼 때 또한 서버사이드렌더링이 실행되는 곳에서 위 함수를 작성해야함을 인지할 수 있고
getInitialProps는 페이지에 요청이 있을 때마다 서버사이드 렌더링을 하니 성능 퍼포먼스가 떨어질 수 있음을 예상할 수 있다.
사용방법은 아래와 같이 async 키워드를 붙여 static method로 작성하면 된다.
import { NextPage } from 'next' interface Props { userAgent?: string; } const Page: NextPage<Props> = ({ userAgent }) => ( <main>Your user agent: {userAgent}</main> ) Page.getInitialProps = async ({ req }) => { const userAgent = req ? req.headers['user-agent'] : navigator.userAgent return { userAgent } } export default Page
getInitialProps를 통해 전달받은 data는 서버에서 준 데이터를 마치 JSON.stringify처럼 serialize하여 전달받을 수 있다.
또한, 하나의 페이지에서는 하나의 getInitailProps만 실행된다.
next 내부에서 페이지가 렌더링될 때 거치는 순서는 _app -> page component이다.
만약 _app에 getInitailProps를 정의했다면 하위 컴포넌트에서는 getInitailProps가 실행되지 않는다.
그렇기 때문에, 하위 컴포넌트에서도 getInitialProps 값을 반영하려면 _app.tsx에 작성하여야 한다.
_app.tsx에서 정의된 getInitialProps의 하위 페이지들이 getServerSideProps를 통해 정의된 page라면 getInitialProps는 서버에서만 오로지 동작하며, next/router나 next/link를 통해 다른 경로로 이동할 때, getServerSideProps가 아닌 페이지라면 클라이언트에서 실행될 수 있다.
2. getServerSideProps
이 역시 서버에서 미리 preRendering해주는 메소드 중 하나이다.
서버에서 미리 데이터가 fetching된 html을 주고 이 후, 브라우저가 hydrate하는 방식을 취하는 hybrid-rendering방식을 취할 때 주로 사용된다.
getServerSideProps는 오로지 서버사이드레서만 실행된다. 그렇기 때문에 web API나 이벤트핸들러등 브라우저가 지원하는 기능을 사용할 수 없다.
또한 getServerSideProps의 return으로 페이지를 렌더링할 때 필요한 JSON을 return해준다.
아래는 Next.js를 풀스택으로 사용했을 때의 예시이다.
export const getServerSideProps: GetServerSideProps = async ( ctx: GetServerSidePropsContext ) => { //data fetching return { props: { carts: JSON.parse(JSON.stringify(carts)), }, }; }; const Cart: NextPage = ({ carts }: any) => { return ( <div>{carts}</div> ); };
getServerSideProps를 통해 data fetching 작업을 수행한 후, 완료된 데이터를 props로 넘겨주고 해당 props를 pages/card.tsx에서 NextPage로 정의하여 fetching된 데이터를 받은 다음 client-side에 렌더링한다.
이러한 방식은 요청과 동시에 fetching된 데이터를 rendering 받고 싶을 때 사용할 수 있다. 또한, getServerSideProps을 이용한 page의 경우 아래와 같이 request headers에 cache-control를 통해 caching할 수 있다.
export async function getServerSideProps(context) { // Add whatever `Cache-Control` value you want here context.res.setHeader( 'Cache-Control', 'public, s-maxage=10, stale-while-revalidate=59' ) const res = await getRequest(API.home) return { props: { home: res?.data?.result } } }
다음의 두 가지 방식은, page에서 외부 데이터를 정적으로 생성할 수 있는 방법이다.
이 중, getStaticProps는 page에서 외부 데이터를 불러올 때, getStaticPath는 외부 데이터와 path가 연동될 때 사용할 수 있다.
3. getStaticProps
getStaticProps는 next build시에 데이터를 가져온다. 이와 반대로 getServerSideProps는 해당 페이지가 요청될 때마다 재요청된다. 그래서 getStaticProps를 통해 구성한 페이지중 fresh한 데이터로 fetching 하기 위해서는 react-query나, redux와 같은 상태관리를 통해 업데이트가 필요하다. getServerSideProps의 경우 페이지를 요청할 때 서버단에서 fresh한 데이터를 json으로 내려주기 때문에 페이지 접속과 동시에 항상 최신 정보를 접할 수 있다.
getStaticProps는 params를 받아 그에 해당하는 paths를 받아온다. 미리 생성된 paths는 캐싱되기때문에 라우터로 페이지를 이동할 때 굉장히 빠른 렌더링 속도를 보여줄 수 있다. 그렇기 때문에 페이지에 자주 업데이트되는 데이터가 표시되거나 모든 요청에 따라 페이지 콘텐츠가 달라지는 경우에는 유용하지 않다. (가령 사용자에게 같은 데이터를 보여줄 때 유용하다)
아래는 공식 문서에서 정의한 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
또한 주의할 점이 있는데, getStaticProps의 경우 오로지 page에서만 작성할 수 있다. 그렇기 때문에 pages 폴더 하위의 _app.tsx, _document.tsx, _error.tsx에서는 동작하지 않는다.
4. getStaticPath
앞서 얘기했 듯, getStaticPath는 외부 데이터에서 데이터를 가져오긴 하는데 path까지 연동될 때(즉 페이지에 동적 경로가 있을 때) 유용하게 사용할 수 있다.
또한 getStaticProps와 마찬가지로 next build시에 데이터를 가져온다.
getStaticPath는 반드시 getStaticProps와 함께 사용되어야 한다.
아래는 공식문서에서 작성된 예제이다.
// pages/posts/[id].js // Generates `/posts/1` and `/posts/2` export async function getStaticPaths() { return { paths: [{ params: { id: '1' } }, { params: { id: '2' } }], fallback: false, // can also be true or 'blocking' } } // `getStaticPaths` requires using `getStaticProps` export async function getStaticProps(context) { return { // Passed to the page component as props props: { post: {} }, } } export default function Post({ post }) { // Render post... }
특정 데이터베이스에 연동되어 있거나, headless CMS, File System에서 데이터를 호출할 때 유용하게 사용할 수 있다.
또한, getStaticProps의 fallback 옵션은 다음과 같이 사용할 수 있다.
fallback: false: getStaticPaths가 반환하지 않은 모든 path에 대해서 404 페이지를 반환
fallback: true: getStaticPaths가 반환한 path들은 빌드 타임에 HTML로 렌더링 되나 이 외의 path들에 대한 요청이 들어온 경우 404 페이지를 반환하지 않고, 페이지의 fallback 버전을 먼저 보여준다.
백그라운드 작업이 끝나면 path에 해당하는 JSON 파일을 받아서 새롭게 페이지를 렌더링한다.
즉 fallback -> 풀페이지와 같은 순서로 화면이 변화한다.
fallback: blocking: true일 경우와 비슷하지만 페이지 생성 중에 fallback 페이지를 반환하지 않고 SSR처럼 동작해서 아무것도 미리 보여주지 않게 된다.
'Frontend > NextJS' 카테고리의 다른 글
Next.js 렌더링 방식 및 react-query를 이용한 hydrate (0) 2023.05.01 Next.js _app, _documnet (0) 2023.05.01 nextJS 왜 쓰는가 (0) 2023.01.19