[Next.js] Next.js 시작하기: 3편

donguraemi·2023년 8월 24일
0

넥스트JS

목록 보기
3/5
post-thumbnail

웹 사이트는 일반적으로 많은 페이지들을 갖고 있다. 어플리케이션에 페이지를 추가하는 방법에 대해 알아보자.

Pages in Next.js

Next.js에서 페이지는 pages 디렉토리의 파일에서 가져온 리액트 컴포넌트다. 페이지들은 파일 이름을 기반으로 경로와 연결된다. 즉, 단순히 pages 디렉토리의 하위 js 파일을 만들면 그 경로가 URL 경로가 된다.

file nameroute
pages/index.js/
pages/posts/first-post.jsposts/first-post

path


웹사이트의 페이지를 연결해야 할 때 우리는 <a> 태그를 사용한다. Next.js에서는 어플리케이션의 페이지들을 연결하기 위해 next/linkLink 컴포넌트를 사용한다.

Link는 Next.js에서 SPA를 매우 쉽게 구현할 수 있도록 도와주는 도구다. SPA는 하나의 페이지에서 모든 작업을 처리하는 앱으로, 서버로부터 가져올 데이터가 있다면 ajax 같은 방법을 이용하여 동적으로 로딩한다.

import Link from 'next/link';

<h1 className='title'>
  Read <Link href='/post/first-post'>this page!</Link>
</h1>

Client-Side Navigation

Link 컴포넌트는 같은 Next.js 어플리케이션의 두 페이지간 클라이언트 측 탐색을 허용한다. 클라이언트 측 탐색은 자바스크립트를 이용한 페이지 전환을 의미한다.


Code splitting and prefetching

Next.js는 자동으로 코드 분할을 제공한다. 따라서 페이지에 필요한 것만 불러온다. 즉. 홈페이지가 렌더링 되었을 때, 다른 페이지의 코드는 초기에 제공되지 않는다. 이는 홈페이지가 수백개의 페이지를 갖고 있어도 빠르게 로드할 수 있음을 의미한다.

요청한 페이지에 필요한 코드만 불러온다는 것은 페이지가 독립적이다는 것이다. 어떤 페이지가 에러를 던지더라도 어플리케이션의 나머지는 여전히 잘 작동한다.

또한 Next.js는 Link 컴포넌트가 브라우저의 뷰포트에 나타나면 자동으로 백그라운드에서 연결된 페이지에 대한 코드를 프리패치한다. 링크를 클릭하면 대상 페이지의 코드를 이미 백그라운드에서 불러왔기 때문에 페이지 전환이 즉각적으로 이루어진다.


Assets

Next.js는 최상위 레벨의 public 디렉토리에서 이미지 같은 정적 자산들을 제공한다.

일반 HTML은 다음과 같이 이미지를 추가한다.

<img src='/images/profile.jpg' alt='Kim Rina' />

하지만 이 방법은 다음을 수동적으로 처리해야 한다.

  • 다양한 화면 크기에 따라 이미지가 반응해야 한다.
  • 타사 도구나 라이브러리를 이용하여 이미지를 최적화해야 한다.
  • 뷰포트에 들어갈 때 이미지를 불러온다.

Next.js는 이를 컨트롤할 수 있는 Image 컴포넌트를 제공한다.


Image Component

next/image는 HTML의 <img> 태그를 확장한 것으로 기본적으로 이미지 최적화를 제공한다. 이미지 크기 조정을 제공하여 뷰포트가 더 작은 장치에 큰 이미지를 전달하는 것을 막을 수 있다.


Using the Image Component

빌드 시에 이미지를 최적화하는 대신, Next.js는 수요가 있을 때 이미지를 최적화한다. 즉, 이미지가 천만 개가 있다하더라도 빌드 시간이 늘어나지 않는다.

import Image from 'next/image';

const YourComponent = () => (
  <Image
    src='/images/profile.jpg'
    height={200}
    width={200}
    alt='Kim Rina' 
  />
);

Metadata

HTML의 <title> 태그처럼 페이지의 메타데이터를 수정하고 싶다면 어떻게 해야 할까?

title은 웹 페이지의 제목을 나타내는 태그다. 웹 페이지 본문에는 보이지 않으며, 브라우저 탭이나 개발자 도구 등에서 확인할 수 있다.

import Link from 'next/link';
import Head from 'next/head';

export default function FirstPost() {
    return (
    <>
        <Head>
            <title>First Post</title>
        </Head>
        <h1>First Post</h1>
        <h2>
            <Link href='/'>Back to home</Link>
        </h2>
    </>
    );
}

Third-Party JavaScript

일반적으로 third-party 스크립트는 사이트에 새로운 기능을 추가하기 위해 사용한다. next/script는 HTML의 <script> 태그를 확장한 것으로 추가적인 스크립트를 가져오고 실행할 때 최적화된다.

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

export default function FirstPost() {
    return (
    <>
        <Head>
            <title>First Post</title>
        </Head>
        <Script
            src='https://connect.facebook.net/en_US/sdk.js'
            strategy='lazyOnload'
            onLoad={() => {
                console.log('script loaded');
            }}
        />
        <h1>First Post</h1>
        <h2>
            <Link href='/'>Back to home</Link>
        </h2>
    </>
    );
}

strategy : 언제 third-party 스크립트를 로드할지 조절한다.


CSS Styling

파일 구조를 살펴보면 두 개의 CSS 파일을 포함한styles 폴더를 볼 수 있다.

  • globals.css : global stylesheet
  • Home.module.css : CSS module

CSS Modules

CSS 모듈은 컴포넌트 레벨의 스타일을 적용할 때 사용한다. CSS 클래스를 불러와 사용할 때, 클래스명을 고유한 이름으로 자동 변환해줌으로써 CSS 클래스명이 서로 중첩되는 현상을 방지해주는 기술이다.

특정 모듈만을 위한 CSS 파일 : [모듈명].module.css

CSS 모듈을 적용한 파일에 작성된 클래스는 아래 코드처럼 styles 객체를 활용하여 프로퍼티 형식을 참조할 수 있다.

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

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

devTools
브라우저의 개발자 도구에서 HTML을 살펴보면 Layout 클래스 이름이 다음과 같은 것을 알수 있다. layout_container__...
이처럼 CSS 모듈은 고유의 클래스 이름을 생성한다. 즉, CSS 모듈을 사용하면 클래스 이름 충돌에 대해 걱정할 필요가 없다.


Global Styles

모든 페이지에 CSS 파일을 로드하고 싶다면 어떻게 해야할까? 글로벌 CSS를 불러오려면 pages/_app.js 파일을 생성해야 한다.

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

_app.js는 어플리케이션의 모든 페이지를 감싸는 최상위 리액트 컴포넌트다. Next.js는 pages/_app.js에 글로벌 CSS 파일을 추가하여 사용할 수 있다.

글로벌 CSS 파일은 어디에나 생성할 수 있고 어느 이름이나 가능하다.

pages/_app.js를 업데이트 할 때는 서버를 재시작해야 한다.


Using clsx library to toggle classes

clsx는 클래스 이름을 쉽게 전환할 수 있는 라이브러리다.

npm install clsx

successerror 타입을 갖는 Alert 컴포넌트를 만들어보자. sucess는 초록색 텍스트, error는 빨간색 텍스트를 표시한다.

/* alert.module.cs */
.success {
	color: green;
}
.error {
	color: red;
}
import styles from './alert.module.css';
import { clsx } from 'clsx';

export default function Alert({ children, type }) {
  return (
    <div
      className={clsx({
        [styles.success]: type === 'success',
        [styles.error]: type === 'error',
      })}
    >
      {children}
    </div>
  );
}

Dynamic Routes

이제 외부 데이터에 의존하는 페이지 경로를 알아보자. Next.js를 사용하면 외부 데이터에 의존하는 경로가 포함된 페이지를 정적으로 생성할 수 있다.

dynamic routes

그림처럼 id라는 외부 데이터에 의존하는 posts 경로를 만들어보자. 먼저, pages/posts의 하위에 [id].js 이름의 페이지 파일을 생성한다.

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

다음으로 페이지와 함께 getStaticPaths 함수를 내보낸다. 해당 함수는 가능한 id 리스트를 반환한다.

export default function Post() { ... }
export async function getStaticPaths() { ... }

마지막으로 getStaticProps를 구현한다.
SSG와 getStaticProps

export default function Post() { ... }
export async function getStaticPaths() { ... }
export async function getStaticProps({ params }) { ... }

how to statically generate pages with dynamic routes


API Routes

api 경로를 사용하면 어플리케이션 내에 api 엔드포인트를 생성할 수 있다. 이를 구현하기 위해서는 pages/api 디렉토리 내에 함수를 생성해야 한다.

api/hello를 만들기 위해서는 pages/api 내부에 hello.js 이름의 파일을 생성한다.

export default function handler(req, res) {
  res.status(200).json({text: 'Hello'});
}

참고자료
ofcourse : title 태그
TCP School : CSS Module
NEXT.js : Navigate Between Pages
NEXT.js : Dynamic Routes

0개의 댓글