[Next] 개념 잡기

Ell!·2021년 12월 28일
0

개념 잡기

목록 보기
3/3

Next.js

이 글은 Next JS의 공식 문서를 읽고 개념을 요약해놓은 글입니다. 자세한 내용은 Next JS 공식홈페이지 참고

next js에서 이룰 수 있는 것들

  • page-based routing
  • prerendering (SSG, SSR)
  • code splitting
  • CSS-in-JS

Create Next.js App

CRA처럼 비슷한 템플릿을 제공

npx create-next-app [프로젝트 제목] --use-npm [디렉토리]

npm run dev -> develop server 구동

page 생성

next js에서 라우팅은 pages안의 file의 이름을 기반으로 한다. 예를 들어,

  • pages/index.jsx === '/' route
  • pages/posts/first === /posts/first route

pages 폴더 안의 디렉토리에 js파일을 만들면, 해당 디렉토리가 url path가 된다.

client-side navigation

client-side navigation은 기존의 browser가 담당하던 페이지 이동을 javascript가 담당한다는 의미.

a태그를 사용하면 전체 페이지 refresh가 일어남.

react-router-dom의 link와 같은 역할. 사용자와 상호작용하여 특정 url로 이동시킴

import Link from 'next/link';

<h1 className="title">
  Read{' '}
  <Link href="/posts/first-post">
    <a>this page!</a>
  </Link>
</h1>

a태그를 Link컴포넌트로 감싸준다.

code splitting and prefetching

next js는 각 페이지 별로 자동으로 code splitting을 해준다.
만약 해당 페이지에 Link가 존재한다면 현재 페이지와 연결된 다른 페이지들을 미리 prefetching해 온다.

Assets, Metadata, CSS

static files

next js는 public 폴더에서 static assets들에 접근할 수 있다.

next js는 기본적으로 사진 사용에 대한 optimization을 제공한다. lazy load도 기본 옵션이다. 이미지가 viewport에 들어오면 loading을 시작한다.

import Image from 'next/image'

const YourComponent = () => (
  <Image
    src="/images/profile.jpg" // Route of the image file
    height={144} // Desired size with correct aspect ratio
    width={144} // Desired size with correct aspect ratio
    alt="Your Name"
  />
)

metadata

<head> 태그 대신 <Head> 컴포넌트를 사용해서 metadata를 작성할 수 있다.

<script> 태그 대신 <Script>컴포넌트를 사용. strategyonLoad attribute에서 load 전략과 load 직 후 취할 행동을 정할 수 있다.

import Head from 'next/head';
import Script from 'next/script';

export default function FirstPost() {
  return (
    <>
      <Head>
        <title>First Post</title>
        <Script
          src="https://connect.facebook.net/en_US/sdk.js"
          strategy="lazyOnload"
          onLoad={() =>
            console.log(`script loaded correctly, window.FB has been populated`)
          }
        />
      </Head>
      <h1>First Post</h1>
      <h2>
        <Link href="/">
          <a>Back to home</a>
        </Link>
      </h2>
    </>
  )
}

CSS

next js는 기본적으로 css-in-js를 built-in으로 제공한다. (styled-components를 사용해도 된다고 한다.) 자동적으로 각 파일마다 임의의 class를 지정해주기 때문에 className 정하는 일로 골치아플 일은 피할 수 있을 듯하다.

import styles from './layout.module.css';

export default function Layout({ children }) {
  return <div className={styles.container}>{children}</div>
}

추가로 next js의 code splitting은 스타일 파일에서도 자동으로 적용된다고 한다.

global CSS

전체 페이지에 적용되는 css 적용을 위해서는 조금 제약이 있다.

pages/_app.js파일을 생성한 후, 해당 파일에서 css를 load해야 한다. 이 파일은 react에서의 App.js와 비슷한 역할을 한다. 다른 모든 페이지에 영향을 주는 top-level 컴포넌트 이다.

styles/global.css 파일을 만들고 해당 파일을 pages/_app.js에서 불러오자.

// _app.js

import '../styles/global.css';

export default function App({ Component, pageProps }) {
  return <Component {...pageProps} />
}

pre-rendering and data-fetching

next js는 모든 페이지를 기본적으로 pre-rendering한다. 각 페이지 별로 html 파일을 미리 생성해놓는다는 이야기다. 각 페이지가 브라우저에 의해 불러와질 때, js코드가 작동하고 페이지의 빈 부분을 채워넣는다.(hydration)

Static Generation vs Server-side Rendering

  • SG : 빌드 시에 미리 html 파일 생성. 요청이 들어오면 미리 생성된 파일들을 건내줌
  • SSR : 요청이 오면 html 파일 생성해서 건내줌

SG와 SSR은 섞어서 사용할 수 있다. 좀 더 실시간 update가 많은 페이지에는 SSR을 사용하자.

Static Generation with and without data

어떠한 page에서는 반드시 외부 데이터가 있어야 html 파일을 생성할 수 있는 경우가 있다. 이러한 경우에는 getStaticProps를 사용하자.

export default function Home(props) { ... }

export async function getStaticProps() {
  // Get external data from the file system, API, DB, etc.
  const data = ...

  // The value of the `props` key will be
  //  passed to the `Home` component
  return {
    props: ...
  }
}

getStaticProps는 next js에게 해당 페이지는 특정 데이터에 의존한다는 것을 알려준다.

getStaticProps

export async function getSortedPostsData() {
  // Instead of the file system,
  // fetch post data from an external API endpoint
  const res = await fetch('..')
  return res.json()
}

getStaticProps는 오직 server에서만 작동한다. client쪽에서는 작동하지 않으며, bundle 파일에도 포함되지 않는다.

development 모드에서는 getStaticProps는 매 요청마다 작동, production 모드에서는 빌드시에만 작동

또한 pages 폴더 안에서는 export 가능하다.

SG보다 SSR을 선택해야 할 때.

미리 사용자의 요청에 맞는 html 파일을 생성할 수 없을 때
매 요청 때마다 새로 데이터를 fetching해와야 할 때는 SSG를 사용해야 한다.

이 경우에는 getStaticProps대신 getServerSideProps를 사용해야한다.

export async function getServerSideProps(context) {
  return {
    props: {
      // props for your component
    }
  }
}

context는 request에 사용할 parameter

Dynamic Routes

getStatickPaths

각각의 page path가 fetching하는 데이터에 의존할 때.

pages/posts/<id> 의 id가 외부에서 불러오는 데이터에 있는 경우.

전체 과정은 다음과 같다.

  1. pages/posts 폴더 안에 pages/posts/[id].js 파일 생성. []는 동적라우팅을 의미한다.
  2. getStaticPaths를 사용해서 id로 사용가능한 값의 배열 return
  3. getStaticProps로 id에 따른 데이터 fetching
import Layout from '../../components/layout'

export default function Post() {
  return <Layout>...</Layout>
}

export async function getStaticPaths() {
  // Return a list of possible value for id
  const paths = getAllPostIds()
     // Returns an array that looks like this:
  // [
  //   {
  //     params: {
  //       id: 'ssg-ssr'
  //     }
  //   },
  //   {
  //     params: {
  //       id: 'pre-rendering'
  //     }
  //   }
  // ]
  return {
    paths,
    fallback: false
  }
}

export async function getStaticProps({ params }) {
  // Fetch necessary data for the blog post using params.id
}

getStaticPaths의 return 값은 array of objects 여야!! 각 object는 params를 key로 가지고 있어야 한다.

getStaticProps는 위에서 처럼 page 컴포넌트로 넘길 props를 return하면 된다.

getStaticPathsgetStaticProps와 마찬가지로 dev모드에서는 매 요청마다, prod모드에서는 빌드 시에 작동한다.

fallback

fallback이 false 이면 getStaticPaths의 return에 없는 라우팅은 404페이지를 낸다.

true일 경우, 404 페이지를 내지 않고 Next.js will statically generate the requested path

blocking일 경우, new paths will be server-side rendered with getStaticProps

catch-all routes

pages/posts/[...id].js/posts/a, /posts/a/b, /posts/a/b/c 모두 catch한다.

이 경우 getStaticPaths에서 다음과 같이 return 해야 한다.

return [
  {
    params: {
      // Statically Generates /posts/a/b/c
      id: ['a', 'b', 'c']
    }
  }
  //...
]

세줄 요약

  1. next는 pre-rendering을 제공(SSG, SSR)
  2. getStaticProps, getServerSideProps, getStaticPaths를 통해서
  3. 생각 이상으로 쉽고, zero-config인 것이 너무 좋음..
profile
더 나은 서비스를 고민하는 프론트엔드 개발자.

0개의 댓글