Next.js 학습 정리
Next.js
Next.js 는 React.js 의 프레임워크이며 다음과 같은 기능들을 가지고 있다.
-
더 빠른 page load 를 위한 자동 code splitting 과 prefetching 지원
-
Built-in CSS 과 Sass 지원, 그리고 모든 CSS-in-JS 라이브러리를 지원
-
pre-rendering (static generation(SSG) 와 server-side rendering (SSR) 모두에서) 를 지원한다.
-
직관적인 page-based routing 시스템 (dynamic routes를 지원한다.)
-
fast page load (component state 유지한채로 page re-load 됨) 를 지원
-
Serverless Function 의 API endpoint 를 build 하기 위한 API routes 지원
-
확장 가능성
위에 나열된 기능들을 하나씩 좀 더 자세히 살펴 보자
📕 code splitting 과 prefetching
Next.js 는 code splitting 을 자동으로 수행한다. 즉, 각 page 는 해당 page 에서 필요한 부분만 render 한다. 예를 들어, home page 가 render 되어 있을 때, 다른 page 의 code 들은 serve 되지 않는다.
이를 통해 우리의 app 에 수백개의 page 가 있더라도 home page 는 빠르게 load 된다.
이는 각각의 page 가 독립되어 있음을 뜻한다. 만약 한 page 에서 error 가 발생해도 app 의 다른 부분들은 여전히 동작한다.
추가적으로, Next.js 의 production build 에서는 브라우저의 화면 상 Link
컴포넌트가 발견되면 자동으로 연결된 page 의 코드들을 background 에 prefetch 한다. Link
를 클릭한 순간에는 이미 background 에 연결된 page 가 load 되어 있다. 이는 page 전환 속도를 매우 증가시킨다.
주의 사항
- Next.js app 에서 외부 page 를 연결할 때는
<Link>
가 아닌<a>
를 사용할 것className
과 같은 attribute 는<Link>
대신<a>
에 추가할 것
Next.js 는 code splitting, client-side navigation 그리고 prefetching (in production) 을 통해 자동으로 app 을 최적화 시킨다.
📕 CSS Styling
Styling 방법 두 가지
-
CSS-in-JS
styled-jsx
styled-components
emotion
SASS 를 사용하려면 ‘sass’ 라이브러리를 받아야한다. (
.scss
로 CSS Modules 을 사용할 때도 마찬가지)
Global css 사용 방법
pages/_app.js
를 생성하고 css 파일을 해당 컴포넌트에서 import 한다.
(_app.js
컴포넌트는 모든 컴포넌트의 최상위 컴포넌트로 자동으로 인식되고 render 된다.)
pages/_app.js 코드
import "../styles/global.css";
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}
pages/_app.js 를 추가하면 dev server 를 반드시 restart 해야한다.
📕 Pre-rendering
Next.js 는 기본적으로 모든 page 를 pre-render 한다. 즉, client-side JavaScript 대신 Next.js 가 각 page 의 HTML 을 미리 생성한다는 의미이다.
Pre-rendering 은 더 좋은 performance 와 SEO 를 이끌어낼 수 있다.
생성된 각각의 HTML 은 해당 page 에 필수적인 최소한의 JavaScript 코드와 관련이 있다.
page 가 browser 에 의해 load 되면, 해당 page 의 JavaScript 코드가 실행되면서 page 를 완전히 interactive 하게 만든다. (이 일련의 과정이 Hydration 이다.)
✅ Pre-rendering 확인 방법
아래의 순서를 따른다.
-
browser 에서 JavaScript 를 disable 시킨다. (크롬에서 하는 방법)
-
링크로 이동해본다.
해당 page 는 CRA 로 build 된 plain React.js app 이다. 즉, pre-render 기능이 없어 JavaScript 가 disabled 된 채로는 page 를 render 할 수 없다. -
이번에는 다음 링크로 이동한다.
해당 page 는 Next.js 로 이루어져 있으므로 JavaScript 가 disabled 된 채로도 pre-render 된 HTML 을 문제없이 보여준다.
Pre-rendering 의 동작 원리를 그림으로 확인해보자.
-
Pre-rendering
최초 Load 시 HTML 을 Pre-render 해서 보여준다.
JS 가 실행되면서 React 컴포넌트가 초기화 되고 page 를 interactive 하게 만든다. (Hydration) -
No Pre-rendering (순수 React app)
최초 Load 시 render 할 HTML 이 없다.
JS 가 실행되면서 React 컴포넌트가 초기화 되고 page 를 interactive 하게 만든다. (Hydration)
📕 Data Fetching
Build-time data fetching
static generation (정적 HTML 생성) 시 외부 Data 를 불러와 render 할 수 있다.
예를 들어 file system 에 접근하거나 외부 API 또는 database 에 query 를 보내는 등의 작업이 필요한 경우이다.
이런 경우 Next.js 에 내장된 getStaticProps
라는 비동기 함수를 사용한다.
getStaticProps
는 production mode 에서 build 시에 실행된다.- 함수 내부에서 외부 data 를 fetch 해오고 page 의 props 로 보낼 수 있다.
구조는 다음과 같다.
// Home 컴포넌트
export default function Home(props) { ... }
// getStaticProps() 함수
export async function getStaticProps() {
// file system, API, DB 등으로 부터 외부 data 를 불러온다.
const data = ...
// return 되는 객체의 'props' key 의 value 는
// 자동으로 'Home' 컴포넌트의 props 로 전달된다.
return {
props: ...
}
}
즉, getStaticProps
는 Next.js 에게 해당 page 에 data 의존성이 존재하는 것을 알리고 build 중 pre-render 시에 그 것을 먼저 해결하도록 한다.
development mode 에서는 편의 상 매 요청마다
getStaticProps
가 실행된다.
getStaticProps
를 통해 외부 API 와 Database 에 접근할 수 있는 이유는 이 함수가 오직 server-side 에서만 실행되기 때문이다. 절대 client-side 에서는 실행되지 않는다. 즉, browser 의 JS bundler 에도 포함되지 않는다. 그러므로 database 에 직접 보내는 query 와 같은 코드를 browser 에 보내지 않고도 사용할 수 있다.
오직 Page 에서만 사용 가능하다.
getStaticProps
는pages
폴더 내의 page 파일에서만 export 가능하다.
그 이유 중 하나는 React 가 page 를 render 하기 전에 모든 data 를 필요로 하기 때문이다.
Development 모드 VS. Production 모드
-
development 모드에서는
getStaticProps
가 매 요청(request)마다 실행된다. -
production 모드에서는 build 시에 실행된다.
build 시에 실행되는 것이 원래의 목적이므로 request 시에만 사용 가능한 data 들에는 접근할 수 없다. 예를 들어 query parameter(url) 나 HTTP header 의 data 에 접근할 수 없다.
Request-time data fetching
만약 request 시에 data fetching 과 HTML 생성이 필요하다면 Server-side Rendering 을 하는 것이 좋다.
server-side Rendering 을 하기 위해서는 getServerSideProps
를 사용한다.
function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`);
const data = await res.json();
// Pass data to the page via props
return { props: { data } };
}
export default Page;
getServerSideProps
의 특징
-
getServerSideProps
가 request 시에 호출되므로, 매개변수인context
는 request 의 세부 parameter 를 담고 있다. -
getServerSideProps
는 request 시에 외부 data fetching 이 필요한 page 를 pre-render 해야할 때만 사용해야 한다. -
server 가 매 request result 를 연산해야하기 때문에, TTFB(Time To First Byte) 는
getStaticProps
보다 느려진다. -
result 는 추가적인 configuration 없이는 CDN 에 cache 될 수 없다.
Client-side Rendering
만약 data 를 pre-render 할 필요가 없고 data 가 자주 update 되어야 한다면, Client-side Rendering 을 사용할 수 있다.
- 외부 data 가 필요하지 않은 page 의 일부를 정적 생성을 사용해 pre-render 한다. (loading ui 를 사용해 data 가 render 될 부분을 표시할 수 있다.)
- page 가 load 되면, client 에서 JavaScript 를 사용해 외부 data 를 fetch 하고 남은 부분을 생성해 page 에 붙인다.
Vanilla JS 를 사용한 기초적인 Web app 의 경우인 것 같다.
client-side rendering 그림으로 이해하기
client-side rendering 사용 예
user dashboard page 를 예로 들 수 있다. user 의 개인정보가 포함된 page 이므로 SEO 와 관련이 없고 pre-render 또한 필요 없기 때문이다.
(data 는 빈번하게 update 되므로 request-time data fetching 이 필요하다.)
Data Fetching 한 줄 요약
Build-time data fetching
getStaticProps
: production 모드일 때 build 시 server-side 에서 실행되는 함수
Request-time data fetching
-
Server-side Rendering :
getServerSideProps
함수 / request 시 외부 data fetching 이 필요한 page 를 pre-render 할 때 사용 -
Client-side Rendering : SEO 와 관련 없고 data 가 자주 update 돼야 할 경우 사용
Reference
Subscribe via RSS