NEXT.js는 기본적으로 다양한 렌더링 전략을 제공한다.
- 클라이언트 사이드 렌더링
- 서버 사이드 렌더링
- 정적 사이트 생성
- 증분 정적 재 생성
서버 사이드 렌더링(Server Side Rendering,SSR)
서버 사이드 렌더링이란?
서버 측에서 페이지를 렌더링 하는 것
이처럼 브라우저에 해당 페이지를 요청하면 서버에서 페이지에 필요한 데이터를 불러와서 완성된 HTML 파일을 응답한다.
💡 그 후, 렌더링이 완료된 페이지를 화면에 렌더링 시키는건데 여기서 두 렌더링은 다른 뜻을 가진다.
1) "렌더링"이 완료된
리액트 컴포넌트와 같이 자바스크립트로 작성되어 있는 페이지를 실제 HTML 코드로 변환하는 과정
2) 페이지를 화면에 "렌더링"
HTML을 화면(브라우저)에 실제로 그려내는 것
서버 사이드 렌더링 과정
렌더링이 완료되고 페이지는 모든 컨텐츠가 채워진 채로 화면에 렌더링된다. 바로 화면에 보여주기 때문에 초기 페이지 로딩이 빠르다.
하지만 화면에 보여준 상태여도 아직 번들링된 자바스크립트를 받기 전이므로 인터렉션은 불 가능한 상태가 된다.
이렇게 받은 자바스크립트 코드들은 HTML 요소들과 서로 연결되고 기존에 상호작용 안되던 기능들의 인터렉션이 가능한 상태가 된다.
💡이러한 과정을 Hydration(수화) 라고 한다. 메마른 HTML 요소들에 마치 단비를 내려주듯 JS 코드를 연결시켜 실제로 버튼이나 인풋 등의 다양한 상호작용이 가능해지기 때문!
최종적인 서버 사이드 렌더링의 과정
서버 사이드 렌더링 적용하기
import Link from "next/link";
import { useRouter } from "next/router";
import { useEffect } from "react";
export default function Home({ name }) {
console.log("home");
//만약 콘솔을 브라우저에서만 실행하고 싶을때, 서버에서는 출력되지 않음
//즉, 클라이언트에서만 작동하는 코드 인 것!
useEffect(() => {
console.log("home mount");
}, []);
return <div>{name}</div>;
}
export const getServerSideProps = async () => {
// SSR을 위해 서버측에서 페이지 컴포넌트에게 전달할 데이터를 설정하는 함수
// 반드시 객체를 반환해야하고 props가 반드시 있어야 하고 이 props 값은 무조건 객체로만 설정되어야 함
// 이 함수는 오직 서버에서만 실행됨!즉, 서버에서만 작동하는 코드
// 주의! 이 함수는 서버에서만 동작하기 때문에 콘솔에 찍히지 않음
console.log("getServerSideProps called");
return {
props: {
// 여기 값들을 모두 Home 컴포넌트로 전달됨
name: "KOREA",
},
};
};
- getServerSideProps ✨
- 코드처럼 넥스트앱에서는 서버측에서 실행되는 코드와 클라이언트측에서 실행되는 코드가 공존한다.
import { fetchCountry } from "@/api";
import SubLayout from "@/components/SubLayout";
import { useRouter } from "next/router";
export default function Country({ country }) {
// 이건 리액트 훅이기 떄문에 서버측에서 이용하는 것이 아니라 클라이언트 쪽에서 이용할 때 사용하면 됨
// const router = useRouter();
// const { code } = router.query;
return (
<div>
{country.commonName} {country.officialName}
</div>
);
}
Country.Layout = SubLayout;
export const getServerSideProps = async context => {
// 이렇게 서버측에서 사용할떄는 context를 사용해서 불러오면 됨.
const { code } = context.params;
let country = null;
if (code) {
country = await fetchCountry(code);
}
return {
props: {
country,
},
};
};
- context ✨
정적 사이트 생성(Static Site Generation, SSG)
정적 사이트 생성이란?
- 서버 측에서 페이지를 빌드 타임에 한번만 렌더링 하는 것
- SSR과 SSG는 비슷하지만 페이지를 언제 생성하는지 그 시점이 둘의 차이를 만듦
- 빠른 페이지 응답을 보장하지만 최신 데이터를 반영하기는 어려움
- 페이지 내부 데이터가 변경되지 않는 페이지에 적절한 렌더링 전략
정적 사이트 생성 렌더링 과정
SSG는 사전에 미리 페이지를 생성해 놓기 때문에 브라우저에서 페이지를 요청하면 완성된 페이지를 반환한다. 미리 생성해놓기 때문에 SSR 보다 응답 속도가 상당히 빠르다는 장점이 있다.
단점은 미리 페이지를 생성하다보니 계속 똑같은 페이지만 응답한다는 것이다. 즉, 최신 데이터를 반영하지 못한다.
따라서 자주 바뀌거나 데이터를 자주 받는 페이지라면 최신 데이터를 반영하지 않으니 사용하지 않는 것이 좋다.
정적 사이트 생성 적용하기
import { fetchCountries } from "@/api";
export default function Home({ countries }) {
return (
<div>
{countries.map(country => (
<div key={country.code}>{country.commonName}</div>
))}
</div>
);
}
// 빌드 할 때 딱 한번 불러옴!
export const getStaticProps = async () => {
// API 호출 코드가 필요함
const countries = await fetchCountries();
console.log("countries 데이터 불러옴");
return {
props: {
countries,
},
};
};
- getStaticProps ✨
💡 그럼 정적 사이트 생성 렌더링 방식에서는 동적 경로는 적용하지 못하는 걸까?
동적 경로에 SSG 적용하기
import { fetchCountry } from "@/api";
import SubLayout from "@/components/SubLayout";
import { useRouter } from "next/router";
export default function Country({ country }) {
return (
<div>
{country.commonName} {country.officialName}
</div>
);
}
Country.Layout = SubLayout;
export const getStaticPaths = async () => {
return {
paths: [{ params: { code: "ABW" } }, { params: { code: "KOR" } }],
fallback: false,
};
};
export const getStaticProps = async context => {
// 서버측에서 사용할때는 context를 사용해서 불러오면 됨.
const { code } = context.params;
let country = null;
if (code) {
country = await fetchCountry(code);
}
return {
props: {
country,
},
};
};
- getStaticPaths ✨
- 동적 경로를 가지는 페이지에 getStaticProps만 사용할 경우 에러가 발생하는데 이때 getStaticPaths를 추가해서 사용해주면 된다.
- 또한 fallback 옵션을 설정해서 옵션에 따라 상태를 전달해준다.
다양한 fallback 옵션 알아보기
일단 SSG를 적용했을 때 과정을 알아보자.
- 빌드 타임에 SSG로 설정된 정적 페이지들을 생성하기 위해
- getStaticPaths를 호출해서 어떤 경로를 갖는 페이지들을 생성할 건지 찾아낸다.
- 그 후, getStaticProps를 호출해서 해당 경로를 받는 데이터를 구해서 페이지 컴포넌트에 전달하고 이 페이지를 빌드 타임에 생성한다.
- 마지막으로 페이지 컴포넌트에 렌더링 된다.
브라우저가 미리 만들어 두었던 페이지를 요청하면 그대로 페이지를 반환한다.
그런데 만약 브라우저가 만들어두지 않은 페이지를 요청한다면?
1) fallback : false 인 경우
존재하지 않는 페이지라고 판단하고 404 페이지를 반환한다.
2) fallback : blocking 인 경우
- 존재하지 않는 페이지여도 해당하는 페이지를 실시간으로 생성해준다. (마치 서버 사이드 렌더링 처럼)
- 생성해준 페이지는 브라우저에 반환하고 서버에 저장한다.
- 다시 요청했을 때 서버 사이드 렌더링 처럼 저장해 둔 페이지를 반환해준다.
- 단, 생성되는 시간이 있기 때문에 그 사이에 로딩이 발생한다.
3) fallback : true 인 경우
- props가 없는 버전을 생성하기 때문에 로딩없이 빠르게 반환해준다.
- 그 사이 props를 계산해서 props의 계산이 완료되면 브라우저에 보내준다.
- 즉, 브라우저는 props가 없는 상태의 데이터가 없는 페이지를 보여주고 난 뒤 데이터를 받아 화면에 렌더링 해준다.
증분 정적 재생성(Incremental Static Regerneration, ISR)
증분 정적 재생성이란?
- 일정 시간을 주기로 정적 페이지를 다시 생성하는 기술
- SSG 방식으로 동작하는 페이지가 일정 시간이 지난 이후에 다시 생성되도록 만들어주는 추가적인 기술이다.
- 단, 타이머 처럼 일정하게 업데이트하는게 아닌 비동기 식으로 작동한다.
이처럼 SSG와 SSR 양쪽의 장점을 가진 강력한 렌더링 방식이라고 할 수 있다.
증분 정적 재생성 적용하기
export const getStaticProps = async context => {
// 이렇게 서버측에서 사용할떄는 context를 사용해서 불러오면 됨.
const { code } = context.params;
let country = null;
if (code) {
country = await fetchCountry(code);
}
return {
props: {
country,
},
revalidate : 3, // 이것만 추가해주면 됨!
};
};
- revalidate ✨
📌
프로젝트로 배우는 React.js & Next.js 마스터리 클래스
'Front-end > Next' 카테고리의 다른 글
Error : useSearchParams() should be wrapped in a suspense boundary at page 해결하기 (0) | 2024.06.26 |
---|---|
Error: NextRouter was not mounted 해결하기 (0) | 2024.05.24 |
[Next] 프로젝트 생성하기 (0) | 2024.04.25 |
[Next] 페이지 라우터(Page Router) 사용하기 (0) | 2024.04.23 |
[Next] Next.js 란? (0) | 2024.04.22 |