유리의 개발새발
[Next] 07. 사전 렌더링과 데이터 페칭 (SSR방식으로 조금) 본문
기존 React나 React Native에서는 어떻게 데이터를 불러왔을까?
나는 주로 useEffect를 사용해서, 컴포넌트가 마운트되면 API 요청을 보내고, 그 응답을 상태값에 저장한 뒤 화면에 렌더링하는 전통적인 방식을 사용해왔다.
그런데 이 방식의 단점, 알고 계신가요?
컴포넌트가 마운트된 이후에 데이터를 요청한다는 점이다.
즉, 사용자가 페이지에 들어왔을 때,
- React는 먼저 빈 화면을 렌더링하고,
- 그다음에 API 요청을 보내고,
- 데이터를 받아오면 그제야 화면이 완성된다.
React 자체도 가볍고 빠른 UI 프레임워크는 아니기 때문에, 여기에 데이터 로딩까지 기다려야 한다면?
사용자는 빈 화면을 보며 기다려야 하고, UX는 자연스럽게 나빠진다.
이러한 문제를 해결하기 위해 Next.js에서는 "사전 렌더링"이라는 개념을 제공합니다.
"사전 렌더링? 아, 그거 화면만 미리 그리는 거 아니었어?"
나도 처음엔 그렇게 생각했어요.
화면만 먼저 렌더링해두고, 실제 데이터는 클라이언트에서 가져오는 줄 알았거든요.
그런데 아니더라고요.
Next의 사전 렌더링은 단순히 UI를 미리 그리는 수준이 아닙니다.
페이지를 요청하기 전에, API 호출까지 서버에서 미리 해두는 기능입니다.
즉, 사용자가 페이지를 열기 전에 이미 데이터를 받아와서, 완성된 HTML을 내려주는 방식인 거죠.
이 방식은 React의 느린 초기 로딩과 데이터 지연 문제를 동시에 해결합니다.
그럼, 어떻게 미리 API를 호출하나요? 그냥 두면 자동으로 해주나요?
아쉽게도 그렇진 않습니다.
하지만 그 전에 다른 문제부터 살펴보죠.
만약 API 서버가 저기 아프리카에 있어서 응답이 느리다거나, 혹은 가져올 데이터가 너무 많아서 오래 걸린다면?
Next.js는 이런 상황도 고려해서, 다양한 사전 렌더링 방식을 제공합니다.
- 페이지를 요청할 때마다 서버에서 렌더링할 수도 있고 (SSR, 서버 사이드 렌더링),
- 페이지를 빌드할 때 미리 만들어둘 수도 있고 (SSG, 정적 사이트 생성)
- 심지어 빌드 후 일정 시간마다 자동으로 갱신하는 방식도 있습니다 (ISR, 증분 정적 재생성).
아마 사용자 경험(UX)이 중요하다는 말이 지나가고, 개발자 경험(DX)이 주가 되는 시대가 온다면..
가장 먼저 사라질 프레임워크는 Next.js가 아닐까요? 제발요.
진짜 잘 만든 건 알겠고, 성능도 인정하지만 뭐 이렇게 신경 쓸 게 많죠?
자, 그래도 할 건 해야죠?
혹시 이 글을 보는 여러분 중에, JSP나 jQuery를 해보셨나요?
- 서버에서 HTML을 만들어서 브라우저에 보내주던 JSP,
- 그리고 그걸 받아서 jQuery로 살짝 꾸미던 시절
그때는 페이지를 새로고침하면 항상 서버에서 새 HTML이 내려왔고, 브라우저는 그걸 그대로 렌더링했죠.
Next.js의 SSR도 이와 아주 유사합니다.
가장 기본적인 사전 렌더링 방식으로, 요청이 들어올 때 마다 사전 렌더링을 진행합니다.
import React from "react";
import type { GetServerSideProps } from "next";
type Post = {
id: number;
title: string;
};
type Props = {
posts: Post[];
};
const HomePage = ({ posts }: Props) => {
return (
<main>
<h1>서버사이드 렌더링 예제</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</main>
);
};
export const getServerSideProps: GetServerSideProps = async () => {
// 여기에 실제 API 요청을 넣습니다. (예시용 가짜 API)
const res = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");
const posts: Post[] = await res.json();
return {
props: {
posts,
},
};
};
export default HomePage;
아? 저 api 쏘는 코드를 HomePage 안에서 쓸 수는 없나? ㅇㅇ 안됨.
정확히 말하면 getServerSideProps는 Next.js의 예약 함수 이름(reserved function name)"입니다.
Next.js는 각 페이지 파일 안에서 export된 함수 중 이름이 getServerSideProps인 것을 자동으로 찾아서:
- 서버 측 렌더링(SSR) 으로 페이지를 처리하고,
- 그 함수가 리턴한 props를 페이지 컴포넌트에 전달합니다.
즉, 이건 Next.js가 내부적으로 약속한 이름이에요.
당신이 "내가 원하는 함수 아무 이름으로 써볼까?" 하고 예를 들어 fetchDataForSSR 이런 이름으로 바꿔버리면
❌ Next는 아예 그 함수를 무시합니다.
✅ 중요! HomePage보다 먼저 getServerSideProps가 호출됩니다!
Next.js는 서버사이드 렌더링을 할 때, 먼저 getServerSideProps를 실행해서 데이터를 가져오고,
그 데이터를 props로 넘긴 후에야 컴포넌트를 렌더링합니다.
그리고 이 getServerSideProps 함수는 반드시 아래 조건을 따라야 합니다:
📌 반.드.시 props라는 프로퍼티를 포함하는 단 하나의 객체만 반환해야 합니다.
return {
props: {
posts: [...],
},
};
🧠 getServerSideProps는 "서버에서만" 실행됩니다
이게 무슨 뜻이냐고요?
서버에서만 실행되기 때문에,
window, document, localStorage 같은 브라우저 객체는 undefined입니다.
예를 들어, 다음과 같이 작성하면 100% 오류 납니다:
export const getServerSideProps = async () => {
console.log(window.location); // ❌ undefined 에러
};
❓그럼 HomePage에서는 window 쓸 수 있나요?
그것도 아닙니다. 정확히는... "항상 가능한 건 아닙니다."
왜냐하면 Next는 HomePage 컴포넌트를 두 번 실행하기 때문입니다:
- 서버에서 먼저 실행해서 HTML을 만들고,
- 그 HTML이 브라우저에 도착하면, 브라우저에서 다시 한 번 실행해서 하이드레이션
즉, HomePage가 서버에서도, 브라우저에서도 모두 실행되기 때문에 초기 실행 시점에 window를 쓰면 역시나 에러가 날 수 있습니다.
아니 ㅆ 그럼 어쩌자고? 난 브라우저 측에서만 실행되는 코드를 작성해야 되는데?
그럴 땐 useEffect()를 쓰면 됩니다.
useEffect는 리액트에서 컴포넌트가 브라우저에 마운트된 후에만 실행되기 때문에,
window, document, localStorage 등 브라우저 API를 안전하게 쓸 수 있습니다.

'Next' 카테고리의 다른 글
| [Next] 09. ISR (4) | 2025.07.31 |
|---|---|
| [Next] 08. SSG (3) | 2025.07.31 |
| [Next] 06. Pre-fetching (0) | 2025.07.29 |
| [Next] 05. Next Navigation (0) | 2025.07.29 |
| [Next] 04. Page Router 라우팅 규칙 (2) | 2025.07.29 |