Next.js에서의 SSR과 SSG


데이터 페칭 방식

Next.js에서 서버로부터 데이터 페칭하는 방식에는 대표적으로 세가지가 있다.
각 방식들을 통해, 서버로부터 데이터를 어떻게 받고 렌더링할지를 개발자가 선택해 활용할 수 있다.

Next.js에서는 아래 사진과 같은 api를 통해 SSR과 SSG를 구현할 수 있다.

차례대로 getStaticProps, getStaticPaths, getServersideProps다.


getStaticProps

SSG 방식이라고 생각하면 된다.

빌드 단계에서 정적 페이지(html)를 미리 생성하고, 서버로부터 미리 그려진 해당 페이지를 받아와 화면에 표시해준다. SSG에 기반을 둔 방식이기에, 데이터 변화가 없이 고정적으로 보여줘야 하는 화면 구성에 있어 활용하는 것이 좋다. 그리고 단순 GET요청으로 페이지만 불러오는 것이기 때문에 후술할 getServersideProps보다 속도 측면에서는 훨씬 우월하다.

따라서, 아래와 같은 경우에 getStaticProps의 사용을 고려할 수 있다.

  • 데이터의 동적 변화가 없는 정적 페이지일 때 (ex. 고정된 대분류 카테고리 화면, 회사 규정, 카테고리 등등)
  • SEO가 필요한 컴포넌트일 때

예시 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// { posts }는 빌드타임에 getStaticProps에 의해 채워진다.
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
);
}

// 이 함수는 빌드타임에 서버사이드에서 호출된다.
export async function getStaticProps() {
// 아래와 같이 데이터를 서버사이드에서 미리 페칭할 수 있다.
const res = await axios.get("your api url here");
const posts = await res.json();

// 여기서 이제 아래와 같이 { props: { posts } }의 형태로 return을 해주면
// 위의 Blog 컴포넌트가 해당 리턴값을 빌드타임에 미리 받아둘 수 있다.
return {
props: {
posts,
},
};
}

export default Blog;

getStaticPaths

getStaticProps와 “함께” 사용해줘야 하는 api다.

getStaticProps는 상술했듯, 미리 html파일을 빌드타임에 생성해두는 방식이다. 하지만 Next.js의 특성상 동적라우팅을 사용하는 경우가 잦다. ex) items/[id].tsx

즉, 동적 라우팅을 사용할 때 어떤 params마다 SSG방식을 사용할지 미리 옵션을 지정해주는 것이라고 생각하면 된다.

1
2
3
4
5
6
7
8
9
10
export async function getStaticPaths() {
const items = await axios.get("https://apiUrl/items");
const paths = items.map(({ id }) => ({ params: { id: `${id}` } }));
// [{id : '1'},{id : '2'}...]와 같이 매핑될 것이다.

return {
paths, //해당 paths (1, 2...)등의 param에 대해서는 정적 페이지 생성을 빌드타임에 실행한다.
fallback: false, // 아래에서 설명하도록 하겠다. (true | false | 'blocking')
};
}

위의 예시에서 만약 items/[1 ~ 10].tsx까지 존재한다고 한다면, 1 ~ 10 까지의 params 중 어디까지 SSG방식을 사용할 것인지 미리 정해줄 수 있는 것이다.

그렇다면 위에서 사용한 fallback 프로퍼티는 무엇을 의미하는걸까?

그것은 바로 “등록되지 않은 params에 대해서는 어떻게 처리할 것인가?”에 대한 핸들링을 위한 프로퍼티다. 나중에 paramsid 11이 추가됐다고 가정했을 때, 해당 id 11은 아직 getStaticPaths에 등록되지 않았기에 이를 어떻게 처리할지 우리 next.js는 모른다. 이 때 fallbacktrue로 설정하면 새로 추가되는 등록되지 않은 params도 빌드 시에 static으로 생성된다. 반대로, false로 설정하면 등록되지 않은 params에 대해선 404 페이지로 연결된다.

fallback: true일 때의 플로우를 조금 더 자세히 작성해보자면 아래와 같다.

  1. fallback 페이지를 사용자에게 임시로 보여준다.
    1. if (router.isFallback) return <Loading/>
  2. 서버에서 SSG를 수행한다. (html 생성)
  3. 생성이 완료되면 해당 페이지가 렌더링 된다.
  4. 이후부터는 해당 params로 접속할 때 SSG가 바로 적용된다.

마지막으로 fallback에서의 blocking은 무엇을 의미할까?

true일 때는 fallback페이지를 보여준 뒤 SSG 후 페이지를 렌더링 해줬다. 하지만 blocking으로 설정된 경우에는 위의 과정을 거치지 않고 서버사이드 렌더링 방식을 통해 static 페이지를 보여주며 → 이후부터는 해당 static 페이지를 동일한 params에 대해 제공해준다. 즉, fallback페이지와 같은 특정 로딩 등의 화면이 존재하지 않는 방식이라고 생각하면 된다.


getServersideProps

getServersideProps = SSR방식이라고 생각하면 된다.
이는 빌드타임이 아닌 런타임에 데이터를 페칭한다는 특징을 갖는다.

SSR방식이기 때문에 당연히 데이터가 동적으로 자주 변하는 컴포넌트에서 활용하는 것이 좋다. 데이터의 요청이 잦고 다양한 경우에는 그에 따라 렌더링 되어야 하는 컴포넌트와 UI도 다이나믹할 것이기 때문이다.

좀 더 자세히 말하자면, 특정 화면을 렌더링하는 데 있어 특정 데이터의 페칭이 필요한 경우에 getServersideProps의 사용을 고려해볼 수 있는 것이다.

대표적인 예로, 로그인을 했을 때의 화면과 안했을 때의 화면이 다른 경우, 위치정보를 받아 현재 위치에 기반한 지도나 정보들을 표시해줘야 하는 경우를 들 수 있다.

따라서, 매 요청마다 서버로부터 데이터를 미리 페칭하여 서버사이드에서 해당 데이터를 활용해 특정 부분(컴포넌트)이나 페이지를 pre-render하여 클라이언트에 보내준다고 이해하면 된다.

예시 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Home({ user }) {
<h1>{user.name}</h1>;
}

// 이 함수는 매 요청마다 호출된다.
export async function getServerSideProps() {
// 외부 API를 통해 데이터를 페칭한다.
const res = await axios.get(`api url`);
const user = await res.json();

// props에 담아 데이터를 컴포넌트에 보내준다.
return { props: { user } };
}

export default Page;

캐싱

getServersideProps를 통해 데이터에 대한 캐싱 기능 또한 활용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 이 값은 10초동안 fresh한 상태로 여겨진다. (s-maxage=10)
// 만약 요청이 10초 안에 다시 발생한다면 이전에 캐시된 데이터는 여전히 fresh한 상태를 유지한다.
// 그리고, 10초 이후 ~ 59초 이전에 요청이 발생하면 해당 데이터는 stale한 상태가 되지만,
// 여전히 바로 렌더링 된다. (stale-while-revalidate=59)

// 새로운 요청이 발생했는데 데이터의 상태가 stale할 경우에는 fresh한 데이터를 다시 받아와 캐싱한다.
export async function getServerSideProps({ req, res }) {
res.setHeader(
"Cache-Control",
"public, s-maxage=10, stale-while-revalidate=59"
);

return {
props: {},
};
}

정리

SSG와 SSR을 조금 비유적으로 표현해보자면, SSG방식은 미리 만들어놓은 햄버거 밀키트를 판매하는 것이고, SSR 방식은 수제버거집에서 고객들이 다양한 요구사항과 메뉴를 주문할 때, 그에 맞는 햄버거를 만들어 판매하는 방식이라고 이해해도 될 것 같다😂.

참조한 자료

Getting Started | Next.js

Next.js 100% 활용하기 (feat. getInitialProps, getStaticPath, getStaticProps, getServerSideProps, storybook)


Author

Hoonjoo

Posted on

2022-07-07

Updated on

2022-07-15

Licensed under

Comments