ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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처럼 동작해서 아무것도 미리 보여주지 않게 된다. 

     

     

     

    참고 : https://nextjs.org/docs/basic-features/data-fetching/

    https://velog.io/@mskwon/next-js-static-generation-fallback

    'Frontend > NextJS' 카테고리의 다른 글

    Next.js 렌더링 방식 및 react-query를 이용한 hydrate  (0) 2023.05.01
    Next.js _app, _documnet  (0) 2023.05.01
    nextJS 왜 쓰는가  (0) 2023.01.19
Designed by Tistory.