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 라는 동적 라우팅을 사용하는 페이지가 있을 경우

  1. 빌드하는 동안 pages/posts/1, pages/posts/2 경로 생성
  2. getStaticProps 를 이용해 해당 페이지들의 HTML 생성