Published on

NextJS의 페이지 생성 방식

NextJS Page Router의 페이지 생성 방식.

  • page router 방식에서는 CSR, SSR, SSG과 SSG을 응용한 ISR 방식 총 네 가지 페이지 생성 방식을 제공한다.

1. CSR (Client Side Rendering)

  • page/index.tsx에서 별도 내장 함수 선언(getStaticProps, getServerSideProps) 없이 pageMethod 내부에서 api 요청을 하는 경우 CSR로 동작.

    • example 1. useEffect를 이용한 api 호출.

      // pages/index.tsx
      import React, { useState, useEffect } from 'react'
      
      export function Page() {
          const [data, setData] = useState(null)
      
          useEffect(() => {
              const fetchData = async () => {
                  const response = await fetch('https://api.example.com/data')
                  const result = await response.json()
                  setData(result)
              }
          }, [])
      
          return <p>{data ? `Your data: ${data}` : 'Loading...'}</p>
      }
      
    • example 2. swr or react-query 등 라이브러리를 사용한 api 호출.

      // pages/index.tsx
      import useSWR from 'swr'
      
      export function Page() {
          const { data, error, isLoading } = useSWR(
              'https://api.example.com/data',
              fetcher
          )
      
          if (error) return <p>Failed to load.</p>
          if (isLoading) return <p>Loading...</p>
      
          return <p>Your Data: {data}</p>
      }
      

2. SSR (Server Side Rendering)

  • page/index.tsx에서 별도 내장 함수 선언(getServerSideProps)를 사용하여 SSR로 동작하도록 설정.

    export default function Page({ data }) {
      // Render data...
    }
    
    export async function getServerSideProps() {
      const res = await fetch(`https://.../data`);
      const data = await res.json();
    
      return { props: { data } };
    }
    

3. SSG (Static Site Generation)

  • page/index.tsx에서 api 요청이 없거나, 별도 내장 함수 선언(getStaticProps)를 사용하여 SSG로 동작하도록 설정.

    export default function Blog({ posts }) {
      // Render posts...
    }
    
    export async function getStaticProps() {
      // 빌드 시점에 `posts`를 받아온다.
      const res = await fetch('https://.../posts');
      const posts = await res.json();
    
      return {
        props: {
          posts,
        },
      };
    }
    

4. ISR (Incremental Static Regeneration)

  • page/index.tsx에서 api 요청이 없거나, 별도 내장 함수 선언(getStaticProps)를 응용하여 지정한 data revalidate 시간마다 정적 페이지를 재생성 할 수 있음.

    export default function Blog({ posts }) {
      // Render posts...
    }
    
    export async function getStaticProps() {
      // 빌드 시점에 `posts`를 받아온다.
      const res = await fetch('https://.../posts');
      const posts = await res.json();
    
      return {
        props: {
          posts,
        },
        revalidate: 10, // 초 단위
      };
    }
    

NextJS App Router의 페이지 생성 방식.

  • app router는 페이지 생성 방식이 별도로 존재하지 않으며, fetch의 설정을 통해 자동으로 페이지를 생성.(route segment config를 통해 지정 할 수도 있다.)

  • app router에서 CSR은 페이지 단위가 아닌 컴포넌트 단위로 사용하는 것으로 개념이 바뀜.

    export default async function Page() {
    // `getStaticProps`와 유사한 동작으로 SSG로 설정.(기본값)
    const staticData = await fetch(`https://...`, { cache: 'force-cache' })
    
    // `getServerSideProps`와 유사한 동작으로 SSR로 설정.
    const dynamicData = await fetch(`https://...`, { cache: 'no-store' })
    
    // `getStaticProps`를 응용하여 `revalidate`속성으로 ISR로 설정.
    const revalidatedData = await fetch(`https://...`, {
        next: { revalidate: 10 },
    })
    
    return <div>...</div>
    }
    
  • route segment config 설정으로 페이지 생성 방식을 강제 할 수 있음.

    // page.tsx | route.ts
    export const dynamic = 'auto';
    export const dynamicParams = true;
    export const revalidate = false;
    export const fetchCache = 'auto';
    export const runtime = 'nodejs';
    export const preferredRegion = 'auto';
    export const maxDuration = 5;
    
    export default function MyComponent() {}
    

NextJS에서 SSR 구현시 react query가 필요할까?

  • 회사에서 진행했던 nextjs 12버전 프로젝트에서는 SSR 구현시 캐싱 관리를 위해 react queryClient를 getServerSideProps / getStaticProps에서 preFetch하는 방식으로 ssr을 구현했었다. 하지만 nextjs 13버전에서 내부 함수로 fetch가 등장하고, 14버전에서는 fetch의 기능이 강화되어 SSR 구현시 react query의 도움 없이도 손쉽게 캐시 관리를 할 수 있게 되었다. 코딩 컨벤션 통일을 위해 react query로 ssr을 구현(링크) 할 수도 있지만, csr이라는 개념이 무색해지고 서버/클라이언트 컴포넌트 라는 개념으로 접근하는 nextjs에서 react query 사용시 클라이언트 컴포넌트로 간주되므로 프레임워크와 언밸런싱이 발생한다. 그리고 아직 react query는 서버 컴포넌트에 대해 완전히 대응 가능한 상태는 아니며, 공식 문서에서도 프레임워크에서 제공하는 fetch tool을 사용할 것을 권장하고 있다.

    It's hard to give general advice on when it makes sense to pair React Query with Server Components and not. If you are just starting out with a new Server Components app, we suggest you start out with any tools for data fetching your framework provides you with and avoid bringing in React Query until you actually need it. This might be never, and that's fine, use the right tool for the job! (링크)

  • 따라서, csr/ssr 모두를 만족하는 lib가 나타나기 전까지, ssr은 nextjs의 fetch를 사용하고, csr에서는 react-query으로 사용하는 투 트랙 방식이 현재로선 최선이라고 생각한다.

ref