Next
Redux
를Next
에서 사용하기 전에 짚어보는 배경지식
CSR (Client Side Rendering)
- 구동 방식이 사용자측에서 이루어진다.
- React와 같은 SPA(Single Page Application)의 기본적인 구동 방식이다.
- 브라우저가 서버에 콘텐츠를 요청한다.
- 서버에 콘텐츠를 요청하게 되면 서버에서는 빈 뼈대의 HTML와 자바스크립트 링크를 보내준다.
- 사용자는 자바스크립트를 다운로드하고, 다운로드 된 자바스크립트가 빈 뼈대의 HTML에 DOM을 동적으로 생성하여 그려낸다.
- 사용자는 위의 모든 과정이 끝나야 화면을 볼 수 있기 때문에, 사용자 경험에 좋지 못하지만, 이후 중복되는 내용은 고정해두고 업데이트 돼야 할 콘텐츠만 동적으로 DOM을 그려내어 교체하기 때문에 이후의 렌더링은 SSR 방식보다 빠르다.
SSR (Server Side Rendering)
- 구동 방식이 서버에서 이루어진다.
- 사용자가 페이지를 요청하면 서버에서는 페이지에 필요한 데이터를 모두 삽입하고 CSS까지 모두 적용해 렌더링 준비를 마친 HTML과 Javscript 코드를 브라우저에 전달한다.
- 모든 데이터가 담긴 HTML을 받았기 때문에 사용자는 빠르게 화면을 받아볼 수 있다.
- 하지만 해당 시점에서는 사용자가 버튼을 클릭하거나 이동하려고 할 때 아무 반응이 없는데, 이는 내용과 스타일이 입혀진 빈 껍데기인 HTML에 불과하고, 아직 자바스크립트가 실행되고 로직이 연결되기 전이다.
- 따라서 사용자가 보는 것과 사용자가 연결되기까지는 간극이 존재하며, 페이지를 이동할 때에 이와 같은 과정이 반복된다.
- 데이터가 전부 들어있는 완성된 HTML을 전송하기 때문에 SEO에 유리하다.
- 초기 구동 속도가 빨라 사용자는 빠른 화면을 볼 수 있게 되기에 사용자 경험에 좋으나, 과정을 매번 서버에서 반복하기 때문에 서버 부하가 높으며 이후 중복되는 부분 또한 다시 렌더링 받기 떄문에 초기 진입은 빨라도 이후의 렌더링은 CSR보다 느린 편이다.
- 초기 렌더링만 SSR이 담당하고 이후 브라우저에서 CSR을 하게 된다.
- 데이터를 가져올 때
useEffect
를 사용했다면,getServerSideProps, getStaticProps, getStaticPaths
을 활용하여 데이터를 불러온다.
getServerSideProps
- Next 초기 렌더링 중
getServerSideProps
를 발견하면 컴포넌트 함수 호출 전에getServerSideProps
를 먼저 호출한다. - API 통신을 통해 받아온 데이터를 컴포넌트의
props
로 전달하며, 함수는 매 호출마다 서버에서 실행된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export async function getServerSideProps(context) {
const res = await fetch(`https://.../data`);
const data = await res.json();
return {
props: {
listData: data,
},
};
}
const Main = ({ listData }) => {
<ul>
{listData.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>;
};
SSG (Static Site Generation)
- 빌드 시에 HTML이 생성되고 매 요청마다 HTML을 재사용한다.
- 각각의 요청마다 HTML을 만드는 SSR보다 높은 성능을 가지기 때문에 권장된다.
- 어플리케이션을 서버에 배포해서 처음 빌드할 떄 렌더링된다. (…next build)
- 이 때, 동적인 데이터가 필요한 부분은 빌드 시에 사전에 요청하여 데이터를 포함한 HTML 파일을 생성한다.
- 사용자가 접속하여 페이지를 요청할 때, 빌드된 HTML 파일을 사용자에게 전달하고, 사용자는 이를 받아 페이지를 렌더링한다.
- 이후 CSR과 유사한 방식으로 동작하며, 렌더링된 페이지가 로드되면서 자바스크립트가 실행되고, 상호작용에 따라 필요한 데이터를 요청하고 업데이트된 콘텐츠를 동적으로 렌더링한다.
getStaticProps, getStaticPaths
와 같은 함수를 사용하여 정적 페이지 생성을 설정해주어야 한다.- 정적인 페이지이기 떄문에 블로그 게시물과 같은 정적으로 생성된 정보를 요청마다 동일한 정보를 반환하는 경우에 사용된다.
getStaticProps
- 서버 측에서만 실행되는 함수로 클라이언트에서는 실행되지 않는다.
- API와 같은 외부 데이터를 받아서 정적 생성을 하기 위한 용도로 빌드 시에만 딱 한 번 호출되며, 정적 파일로 빌드된다.
- Main 페이지가 호출되면
getStaticProps
가 먼저 실행되며props
에 리턴 값을 담아 컴포넌트에 전달한다. - 이 함수가 담긴 페이지가 빌드 될 때 서버에서 API를 호출하여 데이터를 담고, 데이터가 담긴 HTML이 생성되게 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export async function getStaticProps() {
const res = await fetch(`https://.../data`);
const data = await res.json();
return {
props: {
listData: data,
},
};
}
const Main = ({ listData }) => {
<ul>
{listData.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>;
};
getStaticPaths
- 동적 라우터를 사용해서
pages/posts/[id].tsx
란 파일을 만들었을 때,id
에 따라서 다른 글을 보여주고 싶을 때의 예시이다. path
가 외부 데이터에 의존할 때, 빌드 시에id=1, 2, 3
에 해당하는 데이터를 가져와서 페이지를 생성한다.getStaticPaths
로 페이지 마다의 데이터를getStaticProps
로 전달하고, 이를Detail
로 전달하여 정적 페이지를 미리 생성한다.fallback
이라는boolean & blocking
값을 통해, 빌드 시에 생성되지 않은 주소로 사용자가 요청을 할 때의 반환값을 말한다.true
: 빌드 시에 생성되지 않은 페이지로 요청할 때fallback
페이지를 제공하고, 서버에서 정적 페이지를 생성하여 사용자에게 제공한다.false
: 빌드 시에 생성되지 않은 페이지의 요청에404
로 응답한다.blocking
: 빌드 시에 생성되지 않은 페이지로 요청할 때,SSR
방식으로 제작한 정적 페이지를 사용자에게 제공하며, 이후 해당 주소로 요청이 올 경우 정적 페이지로 응답한다.
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
28
29
export const getStaticPaths = async () => {
return {
paths: [
{ params: { id: "1" } },
{ params: { id: "2" } },
{ params: { id: "3" } },
],
fallback: true,
};
};
export const getStaticProps = async ({ params }) => {
const id = params.id;
const res = await axios.get(`https://url/${id}`);
return {
props: {
listData: res.data,
},
};
};
const Detail = ({ listData }) => {
<ul>
{listData.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>;
};
ISR (Incremental Static Regeneration)
- SSG에 포함되는 개념이며, 설정한 시간마다 페이지를 새로 렌더링한다.
- SSG는 빌드 시에 페이지를 생성하기 때문에 데이터가 변경되면 다시 빌드해야 하지만, 일정 시간마다 특정 페이지가 다시 빌드되어 페이지를 업데이트한다.
getStaticProps
와 사용 방법은 같지만revalidate
에 명시된 (초)마다 페이지가 새로 렌더링 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export const getStaticProps = async ({ params }) => {
const id = params.id;
const res = await axios.get(`https://url/${id}`);
return {
props: {
list: res.data,
},
revalidate: 20,
};
};
const Detail = ({ list }) => {
<ul>
{list.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>;
};
Next.js 웹 서버
- 서버를 따로 만든 적이 없음에도 서버에서 렌더링 로직을 처리한다.는 말처럼 자체적으로 웹서버를 가지고 있다.
- 서버에서 실행된다는
getStaticProps, getStaticPaths
Next 서버로 전달되어 실행되고 결과값을 컴포넌트에게 반환한다. - 함수들이 사용되고 있는
page
폴더는 프론트와 백엔드, 서버와 공유하고 있는 공간이며getServerSideProps
함수는 Next 의 자체 서버에서 실행된다.
Hybrid Web App
- 특정 목적을 달성하기 위해 이러한 렌더링 방식을 혼합하여 두 개 이상의 기능이나 요소를 결합한 것을 말한다.
- 페이지 특징 별로 가장 최적화된 렌더링 방식을 선택해서 만들 수 있으며, 한 페이지 내에서도 부분별로 렌더링 방식을 혼합하여 하이브리드 방식으로 만들 수 있다.
1
2
3
4
home => ISR
about => SSG
profile => SSR/CSR
contact => CSR
정리
- 웹 애플리케이션 개발 시, TTV(Time To View)와 TTI(Time To Interact)의 간극을 줄여, 사용자가 볼 수 있는 시간과 실제 사용할 수 있는 시간의 간극을 줄여나갈 수 있거나, 이 간극을 알려줄 수 있는 것이 중요하다.
- SEO 적용이 크게 중요하지 않거나 데이터 pre-rendering이 필요없다면
CSR
- 정적 문서로 충분한 화면이면서 빠른 HTML 문서 반환이 필요하다면
SSG
- 컨텐츠가 동적이지만 자주 변경되지 않는 경우
ISR
매 요청마다 화면이 달라지면서 서버 사이드로 렌더링을 하고자 한다면
SSR
- 사용자의 로그인이 필요한가?
- O => CSR, SSR, Hybrid(CSR/SSR)
- X => 데이터가 변경되는가?
- O => 자주 변경되는가?
- O => SSR, Hybrid(CSR/SSG, SSR)
- X => ISR
- X => SSG
- O => 자주 변경되는가?
2024-03-29
- React는 기본적으로
client
단에서 실행된다. - SEO에 최적화 되어 있지 않다는 것은, 소스 코드를 확인해보면 알 수 있는데, 자바스크립트 라이브러리인 리액트는 초기에 사용자측에서 자바스크립트를 다운로드 받아 코드를 실행시키기 때문에 소스 코드가 비어있는 것을 볼 수 있다.
- 초기에 화면을 새로고침할 시 나타나는 깜빡임 또한 사용자측에서 자바스크립트가 실행되기까지의 간격이다.
- Next.js 는 기본적으로 SSR이 된다.
- 따라서
use client
를 작성하였다고 해서, 클라이언트 측에서 렌더링 되는 것이 아니라 모든 컴포넌트는 우선적으로 서버 단에서 렌더링된다.
- 따라서