Next.js
2023. 2. 10. 20:37ㆍ프로그래밍/JavaScript
- 목차
NextJS
- React 의 SSR을 쉽게 구현할 수 있도록 도와주는 프레임워크
- Pre-Rendering을 통해 페이지를 미리 렌더링하며 완성된 HTML을 가져옴
- 사용자와 검색 엔진 크롤러에게 바로 렌더링 된 페이지 전달 가능
CSR (Client Side Rendering)
- 클라이언트에서 빈 html 파일에 자바스크립트 파일을 해석하여 페이지를 렌더링함
- 자바스크립트가 로드 되지 않은 페이지는 검색엔진 최적화(SEO)에 문제가 됨
SSR (Server Side Rendering)
- 서버에서 자바스크립트를 미리 로딩하여 페이지를 렌더링함
- 클라이언트에서의 자바스크립트 로딩 시간이 줄어듦
- 서버에서 자바스크립트, html, css를 만들기 때문에 검색엔진 최적화(SEO)에 좋음
패키지 설치
npx create-next-app@latest
// TypeScript
npx create-next-app@latest --typescript
NextJS 기본 파일 구조
pages
- 폴더 하위에 페이지들을 생성함 (파일 이름으로 라우팅됨)
- index.tsx === "/" 페이지
- _app.tsx : 공통 레이아웃 작성
- _document.tsx : meta 태그 정의
public
- 이미지 같은 정적 에셋들을 보관함
styles
- 스타일링을 처리해주는 폴더
- 모듈 css는 컴포넌트 종속적으로 스타일링하기 위한 것
확장자 앞에 module을 붙여주어야 함
next.config.js
- Next.js 는 웹팩을 기본 번들러로 사용함
- 웹팩 관련 설정 작성
Link 태그 사용
import Link from "next/link";
const Index = () => (
<div>
<Link href="/post">
<a>Post</a>
</Link>
// 동적 link시 [] 사용
<Link href="/post/[id]">
<a>Post</a>
</Link>
</div>
);
- next 의 Link 태그를 사용하여 페이지 이동
- href 속성 안에 경로 작성
- 동적 link 에는 [] 사용
동적 url
// pages/[id].tsx
import { useRouter } from "next/router";
export default () => {
const router = useRouter();
return (
<p>id: {router.query.id}</p>
);
};
- [] 문법으로 동적 url 생성 가능
- localhost:3000/123 접속 시 router.query.id === 123
Next Router
import { useEffect } from "react";
import { useRouter } from "next/router";
export default () => {
const router = useRouter();
useEffect(() => {
router.prefetch("/test");
}, []);
return (
<button onClick={() => router.push("test")}>Test</button>
);
};
- router.push() : 해당 페이지로 이동
- router.prefetch() : 해당 페이지의 데이터를 먼저 불러옴
Data Fetching
- 리액트 에서는 useEffect 내부에서 데이터를 가져옴
- Next.js 에서는 SSR, SSG 를 이용한 Pre-rendering 으로 데이터를 가져옴
getServerSideProps (SSR)
function Page({ data }) {
...
}
export async function getServerSideProps() {
const res = await axios.get(`https://localhost:3000/user`);
const data = res.data;
return { props: { data } };
}
- 요청할 때 마다 html이 생성되기 때문에 데이터가 계속 업데이트됨
- 컴포넌트에 데이터를 props 로 전달하여 렌더링할 수 있음
- 계속해서 데이터가 변경되어야 하는 페이지에서 사용
getStaticProps (SSG)
function Page({ data }) {
...
}
export async function getStaticProps() {
const res = await axios.get(`https://localhost:3000/user`);
const data = res.data;
return { props: { data } };
}
- html 이 빌드 타임에 생성됨
- 요청할 때 마다 빌드된 html을 재사용함
- 페이지가 미리 렌더링 되어야 하고(SEO) 속도가 빨라야 할 때 사용
- 데이터가 계속 변경되는 페이지에서는 적합하지 않음
getStaticPaths
function Page({ data }) {
const router = useRouter();
if (router.isFallback) {
// fallback: true 일 경우, 해당 페이지를 생성할 때 보여주는 fallback 페이지
return <div>Loading...</div>;
}
...
}
export async function getStaticPaths() {
const posts = await axios.get("https://localhost:3000/posts");
const paths = posts.map(({ id }) => ({ params: { id: `${id}` } }));
// paths: [{ params: { id: "1" }}, { params: { id: "2" }}]
return {
paths,
fallback: true,
};
}
export async function getStaticProps() {
const res = await axios.get(`https://localholst:3000/user`);
const data = res.data;
return { props: { data } };
}
- 동적 라우팅 시, 어떤 페이지를 pre-rendering 할 지 결정함
- paths: pre-render 될 페이지 경로
- fallback
- false: getStaticPaths 에서 리턴하지 않은 페이지는 모두 404로 연결됨
- true: getStaticPaths 에서 리턴하지 않은 페이지 접속 시
- 사용자에게 fallback 페이지를 보여줌
- 서버에서 static 페이지를 생성한 후 사용자에게 보여줌
- 'blocking': static 페이지를 생성하는 동안 fallback 페이지를 보여주지 않음 (SSR 처럼 동작)
return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } },
],
fallback: ...
}
ex. pages/posts/[id].tsx 라는 동적 라우팅을 사용하는 페이지가 있을 경우
- 빌드하는 동안 pages/posts/1, pages/posts/2 경로 생성
- getStaticProps 를 이용해 해당 페이지들의 HTML 생성