Next.js - getStaticProps

ryan·2022년 6월 21일
0

렌더링과 동시에 state에 데이터를 넣고 싶을 때, react에서는 useEffect를 사용하여, componentdidmount를 구현하였다. Next.js에서는 동일한 방법으로 시도를 했더니, 데이터를 받기 전 state의 초기값인 빈 배열이 출력된다. 그 이유는 무엇일까?

pre-rendering

  • Next.js는 pre-rendering이라는 과정을 통해 HTML을 먼저 브라우저에 띄운 뒤 js파일을 입히는 방식이다.

  • 위에서 언급한 문제의 경우도 원인은 pre-rendering에 있다. pre-rendering 특성 상 페이지 컴포넌트 함수가 실행된 뒤에 useEffect가 실행되기 때문이다. 아래의 과정을 통해 더 구체적으로 이해할 수 있다.

브라우저 요청
-> (라우터) -> 페이지(html file, 데이터 x)
-> react (hydrate : react가 페이지를 SPA로 만들고 제어하려는 작업)
-> hydrate과정에서 useEffect 실행. 함수에 데이터를 불러옴
-> 데이터가 있는, 상호작용이 가능한 페이지 완성

  • pre-rendering을 통해 반환된 HTML에 데이터가 포함된 페이지를 사전 렌더링 시키려면 위의 NEXT.JS 내장 pre-renderin process를 조정해야 함.

  • 이를 위해 Next.js는 정적 생성(SSG), 서버 사이드 렌더링(SSR). 2가지의 pre-rendering 방식을 제공한다. 본 포스팅에서는 SSG만을 다룬다.

정적 생성(Static Generation / Static Site Generation)

정적 생성이란

  • 정적 생성은 페이지 컴포넌트가 앱, next프로젝트를 빌드할 때. 즉, 프로덕션을 빌드할 때 사전 렌더링된다.
    • 요청이 서버에 도달했을 때, 서버에서 즉각적으로 페이지를 사전 렌더링하지 않고, 개발자가 프로덕션 사이트를 빌드할 때 사전 렌더링함.
  • 사이트가 배포되면 사전 렌더링한 페이지는 변경되지 않음. (데이터를 업데이트 한 뒤 사전 렌더링한 페이지를 변경해야 한다면 빌드 프로세스를 다시 시작해야하고 다시 배포해야 함.)

Next.js에서 정적 생성 구현

  • nextjs는 이미 정적인 페이지를 생성하고 빌드 프로세스 중에 페이지를 생성함.
  • 페이지 컴포넌트에 데이터를 넣어야 한다면 페이지 컴포넌트 파일 안에서 getStaticProps를 export로 내보내야하며, 이는 페이지 컴포넌트 파일(pages폴더)에서만 작동함.

getStaticProps

  • nextjs는 getStaticProps 함수를 찾아서 사전 렌더링 프로세스 중 이 함수를 실행함.

  • 바로 컴포넌트 함수를 호출하지 않고 반환된 jsx스냅샷을 html 콘텐츠로 사용하지만 컴포넌트 함수를 호출하기 전에 getStaticProps함수를 호출함.

  • getStaticProps함수는 페이지에서 사용할 props를 준비하는 역할을 함.

    • props는 페이지에서 필요한 데이터를 포함한다고 할 수 있음.
  • getStaticProps는 비동기적으로 설정될 수 있음. next는 async(or promise)가 해결될 때(데이터를 불러올 때)까지 기다린 뒤에 컴포넌트 함수에서 사용할 props를 반환함.

  • 이렇게 하면 컴포넌트가 실행되기 전에 데이터를 읽을 수 있어서 데이터가 포함된 컴포넌트를 렌더링할 수 있음.

  • getStaticProps 내부의 코드는 빌드 프로세스 중에 실행되기 때문에 클라이언트 측에서 실행되지 않음.

    • fs 등의 모듈 사용 가능)
    • 사용자의 컴퓨터가 코드가 남지 않음.
  • 반환하는 객체의 key는 props여야함. 반환하는 props는 해당 페이지 컴포넌트 함수의 매개변수로 받을 수 있음

코드 예시

const Homepage = (props) => {
  return <TodoList TodoData={props.todo_list} />;
  // 컴포넌트 함수는 props 객체를 받아서 사용할 수 있다. 
};

// 비동기로 실행이 가능하며, 데이터를 불러온 뒤에 컴포넌트 함수(Homepage)에서 사용할 prop를 반환한다. 
export async function getStaticProps() { 
  // fetch data from an API
  return {
    props: {
      todo_list: DUMMY_DATA,
    },
  };
}

getStaticProps에서 주기적으로 업데이트하기

  • 위에서 생성된 getStaticProps는 빌드 프로세스에서 생성되고 배포되기 때문에, db에 데이터를 추가해도 예전 데이터로 페이지를 보게됨.
  • 데이터가 바뀔 때마다 사이트를 다시 빌드해서 배포할 수 있지만, 데이터 변동 빈도가 높다면 revalidate 속성을 이용할 수 있다.
  • revalidate는 점진적 정적 생성이라는 기능을 가짐.
export async function getStaticProps() {
   // fetch data from an API
   return {
     props: {
       meetups: DUMMY_MEETUPS,
     },
     // 요청이 들어올 때 페이지를 다시 생성할 때까지 nextjs가 대기하는 시간을 작성
     // revalidate속성이 있으면 빌드 프로세스 과정에서 바로 생성되지 않고, 서버에서 몇 초 간격으로 생성됨.
     // 10이라면 요청이 들어온 뒤 10초마다 서버에서 페이지를 다시 생성함.
     // 숫자는 데이터 업데이트 빈도에 맞게 설정해놓으면 좋음.
     revalidate: 3600,
 };

getStaticPath로 dynamic path 구현하기

  • 넥스트 js에게 어떤 동적 매개변수 밸류의 어떤 페이지가 pre-generate되어야 하는지 전달함.
  • 컴포넌트에서 dynamic path를 적용해야 한다면 useRouter를 통해 해결했지만, useRouter는 컴포넌트 함수 안에서만 사용이 가능함.
  • 사용자가 URL의 특정 밸류로 요청을 했을 때 모든 페이지를 pre-generate할 수 없기 때문에, getStaticPath로 사전에 만들어놓을 페이지를 정의할 수 있다.
export async function getStaticPaths() {
  return {
    fallback: false, 
    // fallback 옵션은 사전에 만들어놓을 페이지의 범위를 설정할 수 있다.
    // false : paths에 들어간 모든 경로를 제외하고 404 에러를 띄운다.
    // true : paths에 들어간 경로는 pre-generate하고, 이외의 요청에 대해 동적으로 생성한다. 
    
    paths:
      // paths키 객체 배열, 동적 페이지 버전 당 객체가 하나여야 함. (하드 코딩되어 있지만, API를 통해 동적으로 데이터를 넣어줘야 함)
    // pre-generate할 페이지 경로를 모음
      // 동적 페이지가 여러개 있다면 네스트 객체에 키가 여러 개 있음. 
    [
        {
          params: {
            meetupId: 'm1',
          },
        },
        {
          params: {
            meetupId: 'm2',
          },
        },
      ],
  };
}


export async function getStaticProps(context) {
  // fetch data single meetup
  const meetupId = context.params.meetupId;
  return {
    props: {
      meetupData: {
        image: 'https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/Stadtbild_M%C3%BCnchen.jpg/800px-Stadtbild_M%C3%BCnchen.jpg?20130611211153',
        id: meetupId,
        title: 'A first Meetup',
        address: 'seoul station',
        description: 'this is our first meetup ya y',
      },
    },
  };
}
profile
프론트엔드 개발자

0개의 댓글