CSR SSR SSG ISR 비교
CSR(Client Side Rendering)
![](https://blog.kakaocdn.net/dn/cTnd7G/btsDpvopsUp/iEZbsDY9co6lmNOk5aXJw1/img.png)
- 리액트의 그것.
<div id="root" />
만 있는 html과 javascript파일 1개만 받은 뒤, 클라이언트에서 javascript로 모든 걸 그리는 방식
- 장점: 화면 깜박이 없음, js 캐시 가능
- 단점: SEO제약, 보안, 초기 용량 큼.
SSR(Server Side Rendering)
![](https://miro.medium.com/max/1400/1*jJkEQpgZ8waQ5P-W5lhxuQ.webp)
- 레거시한 블로그, 홈페이지에서 사용하는 방식
- PHP/JAVA 템플릿엔진을 통한 구현
- 서버에서 매 요청마다 HTML을 만들어서 클라이언트에게 내려줌.
- 장점: SEO, 보안, 초기 용량 적음.
- 단점: 화면 깜박임, 서버 부하.
SSG(Static Site Generation)
- pre-rendering: Static한 HTML을 빌드타임에 미리 반들어 둠(SSR는 요청타임에 만들기 시작함).
- 장점: 서버 부하 없음, HTML 캐싱 가능, SEO
- 단점: 동적 컨텐츠 처리가 어려움. 컨텐츠 업데이트가 불가능함. 사용자별 데이터 제공이 어려움.
ISR(Incremental Static Regeneration)
- Static한 HTML을 빌드타임에 미리 만들어 둠 + 일정 시간마다 다시 만듦.
- 장점: 서버 부하 적음. HTML 캐싱 어느 정도 가능, SEO 어느 정도 가능.
- 단점: 실시간 데이터가 아님. 사용자별 데이터 제공이 어려움.
Next.js에서는?
- 4개의 렌더링 방식을 모두 지원한다. ⇒ Next.js의 장점.
- 개발자가 편의에 따라 각 페이지의 렌더링 방식을 선택하면 된다.
Next.js에서 CSR 사용하기
const Example = () => {
const [data, setData] = useState(0);
useEffect(() => {
fetchData().then((res) => setData(res));
}, []);
return (
<main>
<h1>Page</h1>
<p>값: {data}</p>
</main>
);
};
export default Example;
const fetchData = async () => {
const delayInSeconds = 2;
return new Promise<number>((resolve) =>
setTimeout(() => resolve(Math.random()), delayInSeconds * 1000)
);
};
![](https://blog.kakaocdn.net/dn/bnCq9X/btsDpvvbv5P/soIKF7z9Gr4G2DkTL0pezk/img.png)
- 일반적인 React와 사용 방법이 똑같다.
- 그런데, HTML이 root만 있는 것이 아니라, CSR이 아닌 것처럼 렌더링 되어 나온다.
- 즉, Next.js는 초기 상태로 렌더링을 시키고, 그 다음 CSR처럼 정보를 업데이트하는 방식으로 동작한다.
dynamic import
'use client';
import NoSSR from '@/components/NoSSR';
import { useEffect, useState } from 'react';
interface Props {
data: number;
}
const Example = () => {
const [data, setData] = useState(0);
useEffect(() => {
fetchData().then((res) => setData(res));
}, []);
return (
<main>
<h1>Page</h1>
<p>값: {data}</p>
<NoSSR />
</main>
);
};
export default Example;
const fetchData = async () => {
const delayInSeconds = 2;
return new Promise<number>((resolve) =>
setTimeout(() => resolve(Math.random()), delayInSeconds * 1000)
);
};
- Next.js에서 컴포넌트를 가져올 경우, 호출된 컴포넌트는 SSR처럼 동작하게 된다.
import dynamic from 'next/dynamic';
import { useEffect, useState } from 'react';
const NoSSR = dynamic(import('@/components/NoSSR'), { ssr: false });
interface Props {
data: number;
}
const Example = () => {
const [data, setData] = useState(0);
useEffect(() => {
fetchData().then((res) => setData(res));
}, []);
return (
<main>
<h1>Page</h1>
<p>값: {data}</p>
<NoSSR />
</main>
);
};
export default Example;
const fetchData = async () => {
const delayInSeconds = 2;
return new Promise<number>((resolve) =>
setTimeout(() => resolve(Math.random()), delayInSeconds * 1000)
);
};
- 만약 하위 다른 컴포넌트를 CSR 형태로 불러오고 싶은 경우, dynamic import를 사용해야한다.
- 더 깊게 알아보고 싶으면
use client
에 대해 검색해보자.
Next.js에서 SSR 사용하기
interface Props {
data: number;
}
const Example = ({ data }: Props) => {
return (
<main>
<h1>Page</h1>
<p>값: {data}</p>
</main>
);
};
export default Example;
const fetchData = async () => {
const delayInSeconds = 2;
return new Promise<number>((resolve) =>
setTimeout(() => resolve(Math.random()), delayInSeconds * 1000)
);
};
export const getServerSideProps = async () => {
const data = await fetchData();
return {
props: { data },
};
};
![](https://blog.kakaocdn.net/dn/Idb9b/btsDnx7ZM8v/CNWTiIopeZj3IBwzKooH5K/img.png)
- 새로고침 마다 내용이 달라지지만(Next.js에서
getServerSideProps
호출) CSR이 아니라 SSR임을 알 수 있다.
Next.js에서 SSG 사용하기
interface Props {
data: number;
}
const Example = ({ data }: Props) => {
return (
<main>
<h1>Page</h1>
<p>값: {data}</p>
</main>
);
};
export default Example;
const fetchData = async () => {
const delayInSeconds = 2;
return new Promise<number>((resolve) =>
setTimeout(() => resolve(Math.random()), delayInSeconds * 1000)
);
};
export const getStaticProps = async () => {
const data = await fetchData();
return {
props: { data },
};
};
![](https://blog.kakaocdn.net/dn/DGyR0/btsDpvPu9e6/vvzaa8DBzx9nNVbMKlx7ok/img.png)
- 새로고침 마다 내용이 달라지지 않으며(Next.js에서
getStaticProps
를 호출하여 HTML을 빌드타임에 생성함), HTML이 통째로 내려오는 것을 볼 수 있다.
- dev 모드에서는 매번 getStaticProps를 호출하기 때문에 build후에 해야 정상적으로 동작한다.
Next.js에서 ISR 사용하기
interface Props {
data: number;
}
const Example = ({ data }: Props) => {
return (
<main>
<h1>Page</h1>
<p>값: {data}</p>
</main>
);
};
export default Example;
const fetchData = async () => {
const delayInSeconds = 2;
return new Promise<number>((resolve) =>
setTimeout(() => resolve(Math.random()), delayInSeconds * 1000)
);
};
export const getStaticProps = async () => {
const data = await fetchData();
return {
props: { data },
revalidate: 5,
};
};
- 새로고침을 하다 보면, 같은 내용이 나오다가 어느 순간에 다른 내용이 나오는 것을 알 수 있다(Next.js에서
getStaticProps
를 5초마다 호출)
- dev 모드에서는 매번 getStaticProps를 호출하기 때문에 build후에 해야 정상적으로 동작한다.
ISR 동작이 이상한데..?
- 정말로 위 코드가 5초마다 동작하는 지 확인하려고 테스트하다 보면 5초가 아니라 새로고침할 때 마다 바뀔 때도 있고, 5초가 지났는데도 안 바뀌는 경우가 있다.
Next.js의 ISR 동작 방식
- Next.js가 자체적으로 5초마다 polling하는 것이 아니라, 5초가 지난 뒤에 페이지 요청이 오면, 그 때
getStaticProps
를 호출하게 된다.
![](https://blog.kakaocdn.net/dn/PbSjf/btsDqMCPnuj/KRkzPeabLVrGqIKjOnCu8k/img.png)
- response headers를 봤을 때
X-Nextjs-Cache
가 HIT임을 알 수 있다.
즉, 현재 이 페이지가 제일 최신 페이지라는 뜻이다.
![](https://blog.kakaocdn.net/dn/F2cVC/btsDrm416wA/vkRz3PAd4JGkojRcGkftG1/img.png)
- 다시 새로고침을 하면,
X-Nextjs-Cache
가 STALE인데,
이는 이 페이지가 최신 상태가 아니므로, 이제 서야 Next.js가 새로 상태를 불러오게 된다.
- 즉, 새로고침할 때 마다 바뀐 경우는 STALE일 때 새로고침해서 새로운 데이터를 가져왔는데, 그 상태도 STALE이라 다시 가져오게 된 경우.
- 5초가 지났는데도 안 바뀐 경우는 STALE이라 상태를 가지고 오는 도중에(상태 업데이트가 비동기인 경우)페이지를 다시 요청하여 아직 상태 업데이트가 되지 않아 HTML을 만들지 못 한 경우다.
Uploaded by N2T
(24.01.09 13:39)에 작성된 글 입니다.