Next.js는 무엇인가

Next.js는 무엇인가

작성자
태인태인
카테고리
📗 스터디
작성일
2023년 07월 15일
태그
Web

Next.js란?

React를 기반으로 하는 웹 개발 프레임워크의 일종이다.
React는 기본적으로 CSR 방식을 취하는데, 이때 SSR을 사용하기 위해서는 개발 과정에서 직접 환경을 구성해주어야 한다. Next.js는 이러한 과정을 쉽게 할 수 있도록 도와주는 프레임워크이다.
 

Page 기반 라우팅

Next.js에서 페이지 기반 라우팅은 파일과 폴더의 구조를 사용하여 URL 경로를 자동으로 생성한다. 이는 개발자가 복잡한 라우팅 로직을 작성할 필요 없이, 페이지 구조와 URL을 쉽게 관리할 수 있게 해준다.
예를 들어 파일 경로가 pages/signin.tsx 라면 url은 hostname/signin 이 된다.
대괄호를 사용하여 파일 경로를 동적으로 지정할 수 있다. 파일 경로가 pages/users/[username].tsx 라면 대괄호 부분에 변수를 넣어 페이지에 접근할 수 있으며, next/router 의 useRouter() 를 통해 대괄호에 들어가는 변수를 확인할 수 있다.
 

Pre-rendering

Next.js는 모든 페이지를 미리 렌더링 할 수 있도록 지원한다. 이를 'Pre-rendering'이라고 부르며, 페이지를 브라우저에서 로드하기 전에 미리 HTML을 생성한다.
  • SSG (default) : 빌드 시 HTML 파일을 구성
  • SSR : 해당 page에서 getServerSideProps()를 사용할 시, 요청을 받을 때마다 서버에서 HTML을 새로 구성해 반환
page 파일에서 getInitialProps()getServerSideProps() 를 사용하지 않으면 SSG를 사용한다.
 

SSR (Server Side Rendering)

서버에서 HTML을 완성하여 클라이언트로 보내주는 방식이다. SSR을 사용하면 모든 데이터가 포함된 페이지를 사용자에게 바로 보여줄 수 있다. 따라서 CSR(client-side rendering)보다 페이지 구성 속도는 느리지만 콘텐츠 구성은 상대적으로 빠른 셈이다. 또한 SEO(search engine optimization) 구성이 쉽다는 장점도 있다.

hydrate

서버에서 렌더링된 HTML 페이지와 JS 파일을 클라이언트에게 보내면, 클라이언트에서 HTML 파일에 JS 코드를 매칭 시키는 작업이다. 이벤트 등록이나 스타일 적용이 일어난다. SSR과 SSG 모두 Hydrate가 일어나는데, SSG의 경우 빌드타임에 query 가 없기 때문에 런타임에서 query에 대한 hydrate가 일어난다.

getServerSideProps()

Next.js에서 SSR을 사용하기 위해서는 페이지에서 getServerSideProps() 를 통해 데이터를 받아와야한다.
빌드타임에만 실행되는 getStaticProps()와는 달리 getServerSideProps()는 페이지에 대한 요청이 있을 때마다 실행된다.
function Page({ data }) { // 데이터를 통해 페이지 렌더링... } export async function getServerSideProps() { // 페이지를 요청할 때마다 매번 실행된다. // 데이터를 받아온다. const res = await fetch(`https://.../data`) const data = await res.json() // Pass data to the page via props return { props: { data } } } export default Page
 

 

CSR(Client Side Rendering)

빈 HTML파일과 JS파일을 모두 가져와 클라이언트, 즉 브라우저에서 HTML을 구성하는 방식이다. 처음 페이지에 접속하면 빈 HTML 파일을 보여준 후 API 요청과 같은 데이터 처리 이후 데이터를 포함한 페이지(페이지 완료)를 다시 렌더링하기 때문에 사용자가 화면을 인식하는데 상대적으로 오랜 시간이 소요된다. 하지만 페이지간 전환 시 클라이언트에서 화면을 다시 구성하므로 화면 전환 속도가 빠르다는 이점을 갖는다.
Next.js에서 CSR을 사용하는 경우는 두 가지로 나눌 수 있다.
  1. URL을 입력하여 미리 렌더링된 페이지를 받고 useEffect()를 통해 데이터를 추가로 불러오는 경우
  1. <Link/>router.push()를 사용하여 페이지 전환이 일어나는 경우

getStaticProps와 getServerSideProps

  1. getStaticProps(): 빌드 타임에 getStaticProps()가 실행되면 HTML과 함께 JSON 파일도 생성된다. 이 JSON 파일은 next/link나 next/router를 통해 CSR 화면 전환 시 사용된다 getStaticProps를 사용하는 페이지로 이동할 때, 해당 JSON 파일을 받아와 페이지 컴포넌트의 props로 사용한다.
  1. getServerSideProps(): next/link나 next/router를 통해 페이지 전환 시 Next.js가 getServerSideProps를 실행하여 서버에 API 요청을 보낸다.
 

SSG(Static Site Generation)

HTML 파일을 빌드 시에 미리 렌더링하여 생성하는 것이 SSG이다. 이는 주로 정적인 페이지에 사용된다. HTML 파일은 미리 생성되기 때문에 서버에서 매번 연산을 수행할 필요가 없을 뿐만 아니라, 별도의 설정 없이 CDN 캐시를 사용할 수 있어 SSR보다 빠른 속도를 보여준다.
이전에 말한 대로 SSG는 Next.js의 기본 렌더링 방식 중 하나이다. 그러나 백엔드 서버에서 데이터를 받아와 렌더링해야 하는 경우도 고려해봐야 한다. 페이지에서 useEffect()를 사용한다면, SSG에서는 데이터가 필요 없는 부분은 빌드 타임에 구성되고, 데이터가 필요한 부분은 CSR로 렌더링된다. 페이지에서 데이터를 필요로 하는 부분이 많을수록 사용자가 화면을 인식하는 데 시간이 걸리며, 이는 SSG의 이점을 충분히 활용하지 못하게 된다.
이 문제는 Next.js에서 제공하는 페이지 단위 함수인 getStaticProps()를 통해 해결할 수 있다
아래는 getStaticProps()의 예제 코드이다.
function Blog({ posts }) { return ( <ul> {posts.map((post) => ( <li>{post.title}</li> ))} </ul> ) } export async function getStaticProps() { const res = await fetch('https://.../posts') const posts = await res.json() return { props: { posts, }, } } export default Blog
getStaticProps는 빌드 타임에 서버에서 데이터를 가져와 반환하며, 이를 사용하는 페이지는 빌드 타임에 getStaticProps로부터 props를 받아올 수 있다. 따라서 빌드 타임에 데이터에 따른 화면 구성이 가능해진다.
SSG 페이지의 데이터가 변경되면 어떻게 처리해야 할까?

revalidate

SSG는 몇 가지 문제점이 있는데, 그 중 하나는 빌드 타임에 정적 파일을 생성하기 때문에 이후 데이터 변경이 있더라도 페이지에 반영되지 않는다는 것이다. 이를 해결하기 위해 getStaticProps()에는 revalidate 옵션이 있으며 초 단위로 설정할 수 있다.
export async function getStaticProps() { const res = await fetch('https://.../posts') const posts = await res.json() return { props: { posts, }, revalidate: 10, // 초 } }
여기서 10은 10초마다 페이지를 재빌드하겠다는 의미이며, 이후 들어오는 요청에 대해서는 새로 빌드된 페이지를 반환한다.

getStaticPaths()

SSG의 다른 문제점은 동적 라우팅을 사용하는 경우이다. (예: hostname/users/[username])
동적 라우팅을 사용하면 빌드 타임에는 query의 값을 알 수 없다. 따라서 getStaticPaths()를 사용하여 동적 라우팅이 가능한 모든 경로에 대한 정보를 getStaticProps()에 전달할 수 있다.
아래는 공식 문서에서 제공하는 예제이다.
// pages/posts/[id].js function Post({ post }) { // post 렌더링 하는 코드 } export async function getStaticPaths() { const res = await fetch('https://.../posts') const posts = await res.json() const paths = posts.map((post) => ({ params: { id: post.id }, })) return { paths, fallback: false } } export async function getStaticProps({ params }) { const res = await fetch(`https://.../posts/${params.id}`) const post = await res.json() return { props: { post } } } export default Post
 

fallback 옵션

getStaticPaths()에서는 미리 만들어진 경로가 아닌 임의의 경로가 URL로 들어올 경우 어떻게 처리할지에 대한 fallback 옵션이 있다.
export async function getStaticPaths() { return { paths: [ { params: { ... } } ], fallback: true, // true || false || "blocking" }; }
fallback 값에 따라 경로가 미리 정의되지 않은 경우 getStaticProps()의 동작이 달라진다.
  • false: 404 페이지를 반환한다.
  • true: 먼저 페이지의 fallback 버전을 보여주고 getStaticProps를 통해 요청을 보내서 HTML 파일과 JSON 파일을 만든다. 만들어지면 브라우저는 JSON 파일을 받아서 렌더링한다. 이후 Next.js는 만들어진 HTML 파일을 미리 렌더링된 페이지 목록에 추가한다. 이후 요청부터는 미리 렌더링된 HTML 파일을 반환한다.
  • blocking: true와 비슷하게 작동하지만, 파일을 렌더링하는 동안 fallback 버전을 보여주는 것이 아니라 SSR처럼 작동하여 HTML 파일을 생성하고 반환한다. 이후 요청부터는 생성된 HTML 파일을 반환한다.
true 옵션과 blocking 옵션은 next export에서는 작동하지 않는다.
 

Fallback Page

getStaticPaths()에서 fallback: true이면 먼저 fallback 페이지를 보여준다고 했는데, 이 fallback 페이지는 정확히 무엇일까?
사실 fallback 페이지도 개발자가 만들어야 합니다. getStaticPaths()는 getStaticProps()로 페이지에 isFallback: true를 전달할 뿐이다. 페이지에서 useRouter()의 isFallback을 통해 조건을 분기하여 fallback 페이지를 보여줄 수 있다.
// pages/posts/[id].js import { useRouter } from 'next/router' function Post({ post }) { const router = useRouter() if (router.isFallback) { return <div>Loading...</div> } // post 렌더링 하는 코드 생략... } export async function getStaticPaths() { return { paths: [{ params: { id: '1' } }, { params: { id: '2' } }], fallback: true, } } export async function getStaticProps({ params }) { const res = await fetch(`https://.../posts/${params.id}`) const post = await res.json() return { props: { post }, revalidate: 1, } } export default Post
 

요약

Next.js는 서버 사이드 렌더링(SSR)과 클라이언트 사이드 렌더링(CSR)을 모두 지원하는 React 프레임워크이다. 또한, 정적 사이트 생성(SSG) 기능도 제공한다. 이는 빌드 시에 HTML 파일을 미리 생성하고, 필요한 데이터를 불러와 렌더링하는 방식이다. getStaticProps() 함수를 사용하면 빌드 타임에 데이터를 가져와 화면을 구성할 수 있다. 또한, getStaticPaths() 함수를 사용하면 동적 라우팅이 가능한 모든 경로에 대한 정보를 getStaticProps()에 전달할 수 있다. 이 외에도 revalidate 옵션과 fallback 옵션 등을 통해 페이지의 데이터 변경이나 미리 정의되지 않은 경로에 대한 처리도 가능하다.

댓글

guest