
🌱 해당 포스트는 한 입 크기로 잘라먹는 Next.js(v15)을 수강하고, Next.js 공식 문서 - page router를 참고하여 정리한 글입니다.
Next.js에서는 다양한 사전 렌더링 방식을 제공한다. 이번 포스트에서는 Page Router에서 서버 사이드 렌더링(SSR) 방식을 어떻게 구현할 수 있는지에 대해 알아보려고 한다.
만약 페이지가 서버 사이드 렌더링(SSR) 을 사용한다면, 해당 페이지의 HTML은 매 요청마다 생성된다. 페이지를 SSR로 만들고 싶다면, getServerSideProps 함수를 사용한다. 이는 Next.js 프레임워크의 일종의 문법으로 받아들일 수 있다.
getServerSideProps 함수는 컴포넌트보다 먼저 실행되어서, 컴포넌트에 필요한 데이터를 불러오는 함수이다. getServerSideProps 함수를 만들어 주기만 하면, 해당 페이지는 SSR로 사전 렌더링을 진행한다.
❗️
getServerSideProps함수는 사전 렌더링 과정에서 서버 측에서만 딱 한번 실행된다.
따라서getServerSideProps함수에서console.log()를 실행하면, 해당 출력은 next 서버에서만 보이고, 브라우저에서는 보이지 않는다.
export default function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
getServerSideProps는 리턴 값으로 반드시 props라는 property를 포함하는 객체를 반환해야한다. 이때 props 객체가 컴포넌트의 props로 들어가게 되고, 컴포넌트에서 사용할 수 있게 된다.
// src/pages/index.tsx
import SearchableLayout from "@/components/searchable-layout";
import { ReactElement } from "react";
/* import 구문 생략 */
// ⭐️ getServerSideProps 함수를 만들어 주기만 하면, 해당 페이지는 SSR로 사전 렌더링을 진행한다.
// "/" 경로로 접속해 index 페이지를 요청받아 사전 렌더링을 진행할 때, Home 컴포넌트보다 먼저 실행된다.
// 그래서 index 페이지에 필요한 데이터를 불러오는 기능(ex. 다른 백엔드 서버로부터 데이터 페칭)을 제공한다.
export const getServerSideProps = () => {
// 컴포넌트보다 먼저 실행되어서, 컴포넌트에 필요한 데이터를 불러오는 함수
const data = "hello";
return { props: { data } };
};
export default function Home({data}: any) {
console.log(data);
return (
<div className={style.container}>
/* 코드 생략 */
</div>
);
}
아래 console의 log는 위 예시 코드를 실행한 결과이다.
getServerSideProps 는 사전 렌더링 과정에서 한 번 실행된다. Home 컴포넌트의 경우, 사전 렌더링 시 한 번 실행되고, 클라이언트에서 hydration을 위해 한 번 실행된다. (총 두 번 실행)
따라서 컴포넌트에서도 클라이언트 API(window 객체 등)에 아무런 조건 없이 접근하면, 아래와 같이 에러가 난다.

❗️ 만약 브라우저 API를 사용해야 해서, 브라우저 측에서만 실행되는 코드를 작성하고 싶다면?
여러가지 방법이 있지만, 가장 쉬운 방법은useEffect를 사용하는 것이다.export default function Home({ data }: any) { // 컴포넌트 마운트 이후, 실행 useEffect(() => { console.log(window); }, []); return ( <div className={style.container}> /* 코드 생략 */ </div> ); }코드 실행 결과 (브라우저)

ƒ (Dynamic) server-rendered on demand
getServerSideProps 함수를 사용하니까, 바로 페이지의 사전 렌더링 방식이 서버 사이드 렌더링(SSR) 으로 바뀐 것을 볼 수 있다. (꼭 getServersideProps 함수를 구현하지 않아도, 해당 함수가 있다면 SSR로 바뀐다)
getServerSideProps 함수 자세히 알아보기getServerSideProps 로 받아오는 데이터의 typeNext.js에서 내장 타입을 제공하고 있다. InferGetServerSidePropsType<typeof getServerSideProps> 를 사용해서, props의 타입을 지정해줄 수 있다.
export default function Home({
data,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
return (
<div className={style.container}>
/* 코드 생략 */
</div>
);
}
getServerSideProps의 인자 값: contextgetServerSideProps(context) 함수는 호출 시 context 객체를 인자로 받는다.
context 객체의 타입은 Next.js 내장 타입인 GetServerSidePropsContext이다.
⇒ query가 필요할 때 사용하면 유용하다.

getServerSideProps의 동작 방식
getServerSideProps는 서버에서만 실행됩니다.- 오직 페이지 컴포넌트에서만
export할 수 있습니다.- 반환값은
JSON형식입니다.- 사용자가 해당 페이지에 접근하면,
getServerSideProps가 호출되어 데이터를 가져오고, 그 데이터를 바탕으로 초기 HTML을 렌더링합니다.props로 전달된 값은 클라이언트에서도 초기 HTML 안에 포함되므로 민감한 정보는 절대 포함시키지 말아야 합니다.- 사용자가
next/link나next/router를 통해 페이지에 접근할 경우, Next.js는 서버에 API 요청을 보내고, 서버는getServerSideProps를 실행합니다.getServerSideProps는 서버에서 실행되기 때문에, 별도의 API Route를 만들 필요 없이 CMS, 데이터베이스, 외부 API 등을 직접 호출할 수 있습니다.getServerSideProps안에서 사용할 모듈은 파일 최상단에서 import할 수 있습니다.- 이때
import한 모듈은 클라이언트에 번들링되지 않기 때문에 서버 전용 코드도 작성할 수 있습니다. ⇒ 즉, 데이터베이스 쿼리, 보안 토큰 처리 등 클라이언트에 노출되어선 안 되는 코드를 안전하게 작성할 수 있습니다.
getServerSideProps이 있는 page에 방문한 경우?초기 접속 이후에 페이지 이동이 발생하면, Client Side Rendering (CSR)로 작동하는데, 만약 해당 페이지가 getServerSideProps 함수를 포함하고 있다면 어떻게 될까?
해당 페이지의 JS 코드와 함께 getServerSideProps을 실행한 결과 (props)를 JSON 형식으로 전달해준다. ⇒ 관련 질문 링크🔗
