FE/Next.js

Next.js 시작하기 - (3) Pre-rendering, Data Fetching

SH_Roh 2022. 10. 6. 04:50
반응형

Series

Next.js 시작하기 - (1) Project setting, Routing

Next.js 시작하기 - (2) CSS-in-JS, Custom App

Next.js 시작하기 - (3) Pre-rendering, Data Fetching


 Pre-rendering 

기본적으로 next.js는 모든 페이지를 pre-render한다. 이는 각 페이지에 대해 html을 미리 만들어두는 것을 의미한다.

Initial Load 과정에서는 자바스크립트 동작이 없는 html을 먼저 화면에 보여주는데, 아직 js 파일이 로드되기 전이므로 <Link />와 같은 컴포넌트는 동작하지 않는다.

 

Initial Load에서 html을 로드한 뒤, js 파일을 서버로부터 받아 html을 연결시키는 과정이 일어나는데 이를 Hydration이라고 한다. 해당 과정에서 react 컴포넌트는 초기화되고 사용자와 상호작용할 준비를 마친다.

 

만약 pre-rendering이 없다면 자바스크립트 전체가 로드되어야 하기 때문에 최초 load에서 사용자에게 아무것도 보여지지 않게된다.

 

아래는 간단한 예시 코드이다.

pages/counter.tsx

import { useState } from "react";

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Counter</h1>
      <div>{count}</div>
      <button onClick={() => setCount((prev) => prev - 1)}>-</button>
      <button onClick={() => setCount((prev) => prev + 1)}>+</button>
    </div>
  );
};

export default Counter;

 

+, - 버튼을 누르면 숫자가 증가, 감소되는 간단한 카운터이다.

 

 

네트워크 탭에서 맨 처음으로 생기는 document를 보면 "__next"라는 id의 div안에 카운터의 초기 값들이 pre-render 되어있는 것을 확인할 수 있다.

(실제로 자바스크립트를 disable해놓고 페이지를 로드하면 버튼은 아무 동작도 하지 않고 html만 존재한다.)

 

 

pre-rendering에는 두 가지 형태가 있다.

 

SSG(Static Site Generation): html을 빌드타임에 생성하고 각 리퀘스트에서 재사용된다.

SSR(Server Side Rendering): html을 각 리퀘스트가 일어날 때마다 생성하는 방식이다.

 

development mode(npm run dev)에서는 페이지들이 매 요청마다 pre-rendered된다. (개발의 편의를 위해 개발 모드에서는 static generation도 마찬가지로 매 요청마다 pre-render한다.)

각 페이지에 어떤 종류의 pre-rendering을 사용할 지 선택할 수 있다.

 

공식문서에 따르면 가능한 SSG를 추천한다. 페이지가 한 번에 빌드될 수 있기 때문이다. 이는 모든 리퀘스트마다 페이지가 render되는 것 보다 빠르다.

하지만 만약 유저의 요청 전에 pre-render를 할 수 없는 경우라면 SSR을 쓰는 것이 더 좋을 수도 있다. (ex. 데이터를 자주 업데이트하거나 매 요청마다 콘텐츠가 달라지는 경우 등)

 


 Data Fetching 

Next.js에서 데이터를 fetching하는 방법은 총 4가지가 있다.

 

CSR(Client Side Rendering)

import { useEffect, useState } from "react";
import axios from "axios";

const DateTime = () => {
  const [dateTime, setDateTime] = useState("");

  useEffect(() => {
    axios
      .get("https://worldtimeapi.org/api/ip")
      .then((res) => setDateTime(res.data.datetime))
      .catch((e) => console.error(e));
  }, []);

  return <div>{dateTime || "불러오는 중 ..."}</div>;
};

export default DateTime;

일반적인 react에서처럼 useEffect를 사용해 data를 fetch해오는 방식이다.

 

SSR(Server Sider Rendering)

import { GetServerSideProps, InferGetServerSidePropsType } from "next";
import axios from "axios";

const DateTime = ({ dateTime }: InferGetServerSidePropsType<GetServerSideProps>) => {
  return <div>{dateTime || "불러오는 중 ..."}</div>;
};

export default DateTime;

export async function getServerSideProps() {
  const res = await axios.get("https://worldtimeapi.org/api/ip");

  return {
    props: {
      dateTime: res.data.datetime,
    },
  };
}

getServerSideProps라는 서버에서 실행되는 async 함수를 사용한다. getServerSideProps라는 비동기함수를 export하면 next는 이 페이지를 빌드타임에 이 함수에서 리턴한 값(위 코드에서 dateTime)을 컴포넌트에 props로 전달한다.

 

SSG(Static Site Generation)

import axios from "axios";
import { GetStaticProps, InferGetStaticPropsType } from "next";

const DateTime = ({ dateTime }: InferGetStaticPropsType<GetStaticProps>) => {
  return <div>{dateTime || "불러오는 중 ..."}</div>;
};

export default DateTime;

export async function getStaticProps() {
  const res = await axios.get("https://worldtimeapi.org/api/ip");

  return {
    props: {
      dateTime: res.data.datetime,
    },
  };
}

getStaticProps라는 async 함수를 사용한다. SSR과 마찬가지로 getStaticProps 함수에서 리턴한 값을 컴포넌트에 props로 전달한다.

 

이 때 주의할 점은 SSG를 테스트해볼 때는 yarn build를 한 후, yarn start로 실행을 해주어야 한다는 것이다. (이렇게 하지 않으면 새로고침할 때마다 시간이 바뀐다. production 모드로 실행하면 페이지를 reload를 해도 dateTime이 바뀌지 않는 것을 확인할 수 있다.)

 

ISR(Incremental Static Regeneration)

import { GetStaticProps, InferGetStaticPropsType } from "next";
import axios from "axios";

const DateTime = ({ dateTime }: InferGetStaticPropsType<GetStaticProps>) => {
  return <div>{dateTime || "불러오는 중 ..."}</div>;
};

export default DateTime;

export async function getStaticProps() {
  const res = await axios.get("https://worldtimeapi.org/api/ip");

  return {
    props: {
      dateTime: res.data.datetime,
    },
    revalidate: 5,
  };
}

ISR은 SSG의 장점을 취하면서 단점을 보완할 수 있도록 만들어진 방식이다.

 

getStaticProps로 빌드 시 데이터를 받아오되, 일정 시간이 지난 후의 페이지 요청에 대해서는 함수가 다시 실행된다. (일정 시간이 지나기 전에는 SSG로 동작하다가 일정 시간이 지난 후에는 SSR로 동작을 한다고 보면 된다.)

 


References

Pre-rendering and Data Fetching

Data Fetching Overview

[Next.js] Data Fetching을 하는 4가지 방법

 

 

 

반응형