Next.js에선 기본적으로 모든 페이지를 PreRender
한다. 즉 HTML이 클라이언트 사이드에서 자바스크립트를 통해 생성이 되는 게 아니라 Next.js가 사전에 각 페이지를 만들어 놓는다. 이때 각 HTML은 해당 페이지에 최소한으로 필요한 자바스크립트 코드와 결합되어있다.
페이지가 브라우저에 의해 로드될 때는 hydration
이라는 프로세스를 거치게 된다. hydration은 자바스크립트 코드가 실행되어 해당 페이지를 완전히 인터렉티브하게 만드는 것을 의미한다.
프리 렌더링을 할 경우, 프리 렌더링을 하지 않을 때보다 더 나은 성능과 SEO를 갖출 수 있다.
Next.js
는 프리 렌더링 및 서버사이드 렌더링을 포함한 페이지 렌더링을 위한 런타임으로 Node.js
를 사용한다.
Next.js의 pre-rendering 형태는 Static Generation과 Server Side Rendering으로 나뉘며 각 페이지별로 다르게 적용할 수 있다. 이 pre-rendering 방식의 차이는 HTML을 생성할 때에 있다.
서버에서 요청할 때 즉시만드느냐 혹은 미리 만들어 놓느냐에 따라 차이가 있다.
SSR
은 요청시 서버에서 즉시 HTML을 만들어서 응답하기 때문에 데이터가 달라져서 미리 만들어 두기 어려운 페이지에 적합하다.
반면 SSG
는 미리 다 만들어두고 요청시에 해당 페이지를 응답하기 때문에 바뀔일이 거의없어서 캐싱해두면 좋은 페이지에 사용된다.
기존 pages 라우터 방식
// pages/index.js
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
새로운 앱 라우터 방식
// app/layout.js
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
// app/page.js
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
경로의 각 폴더는 경로 세그먼트를 나타낸다. 각 경로 세그먼트는 URL 경로의 해당 세그먼트에 매핑된다.
경로 세그먼트의 특수 파일에 정의된 React 구성 요소는 특정 계층 구조로 렌더링된다.
export default function Page({ params }: { params: { slug: string } }) {
return <div>My Post: {params.slug}</div>
}
app/blog/[slug]/page.js => /blog/a => { slug: 'a' }병렬 라우팅을 사용하면 동일한 레이아웃에서 하나 이상의 페이지를 동시에 또는 조건부로 렌더링할 수 있다.
React 및 Next.js에서 스트리밍이 작동하는 방식을 배우려면 SSR(서버 측 렌더링)과 그 제한 사항을 이해하는 것이 좋다.
이 단계는 순차적이고 차단적이다. 즉, 모든 데이터를 가져온 후에만 서버가 페이지에 대한 HTML을 렌더링할 수 있다. 그리고 클라이언트에서 React는 코드가 로드된 후에만 UI를 수화할 수 있다.
스트리밍을 사용하면 페이지의 HTML을 더 작은 청크로 나누고 점진적으로 해당 청크를 서버에서 클라이언트로 보낼 수 있다.
이를 통해 UI가 렌더링되기 전에 모든 데이터가 로드될 때까지 기다리지 않고 페이지의 일부를 더 빨리 표시할 수 있습니다. 우선순위가 더 높거나 데이터에 의존하지 않는 구성 요소가 먼저 전송될 수 있으며 React는 더 일찍 수화를 시작할 수 있다.
또한, loading.js 파일을 만들어서 트리밍 형태의 로딩 UI를 생성할 수 있음. loading.js 파일을 생성하면 React Suspense를 자동으로 래핑하여 로딩 화면을 보여주고, 라우트 세그먼트의 내용을 로드하는 동안 서버에서 즉시 로딩 상태를 표시하고, 렌더링이 완료되면 자동으로 새로운 콘텐츠로 교체됨
// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
fetch(URL, { cache: 'force-cache' });
// This request should be refetched on every request.
// Similar to `getServerSideProps`.
fetch(URL, { cache: 'no-store' });
// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
fetch(URL, { next: { revalidate: 10 } });