[Next.js] 코드 스플리팅과 라우팅 관련

시작

$ npx create-next-app next-tutorial --typescript

Head

pages/index.tsx의 내용을 보면 react-helmet와 같이 Head를 통해서 헤더를 관리할 수 있다. (이걸 사용해서 페이지별로 문서의 타이틀도 정할 수 있고 검색엔진 최적화에도 도움이 될 수 있을 것 같음)

// pages/index.tsx

import type { NextPage } from 'next';
import Head from 'next/head';

const Home: NextPage = () => {
  return (
    <div>
      <Head>
        <title>타이틀 지정</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <p>hello world</p>
      </main>
    </div>
  )
}

export default Home

라우팅처리

react에서 라우팅 처리를 위해 react-router-dom을 추가적으로 설치했다면 next.js는 추가적인 설치 없이 pages라는 디렉토리에 기반하여 라우팅을 할 수 있다.

이제 pages 디렉토리 하위에 search.tsx를 생성하고나면 다음과 같이 url로 페이지 이동이 가능한 것을 확인할 수 있다.

// pages/search.tsx

import Head from "next/head";

const Search = () => {
  return (
    <div>
      <Head>
        <title>검색 페이지</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <p>Search</p>
    </div>
  );
}

export default Search;

처음에 파일명을 Search.tsx 대문자로 하였을 때는 url을 쳤을 때 자동으로 대문자에서 소문자로 리다이렉트되어 404 에러가 발생하였다.
https://nextjs.org/learn/basics/navigate-between-pages/pages-in-nextjs
에서도 파일명은 소문자로 시작하는 걸 보면 지켜줘야하는 약속인 것 같다.

Client-Side 네비게이션

react에서도 외부페이지로 이동하지 않는 한 react-router-dom에서 제공해주는 기능으로 어플리케이션 내부에서 페이지 이동을 한 것처럼 next.js에서는 Link라는 컴포넌트를 사용해서 페이지간의 이동을 한다.

메인에서도 사용하고 검색에서도 사용하기 때문에 컴포넌트로 따로 만들어주고

// components/Navigation.tsx

import Link from "next/link";

const Navigation = () => {
  return (
   <header>
    <ul>
      <li>
        <Link href='/'>
          <a>Main</a>
        </Link>
      </li>
      <li>
        <Link href='/search'>
          <a>Search</a>
        </Link>
      </li>
    </ul>
   </header>
  );
}

export default Navigation;

메인페이지와 검색페이지에 Navigation 컴포넌트를 불러와주면 다음과 같이 페이지간에 리로드 없이 이동이 가능해진다.

// pages/search.tsx

const Search = () => {
  return (
    <div>
      <Head>
        // 생략...
      </Head>
      <Navigation />
	  // 생략...
    </div>
  );
}

코드 스플리팅

그리고 추가적으로 pages내의 파일들은 빌드 과정에서 분할되는 코드 스플리팅을 자동적으로 지원해준다고 한다.

Each file inside your pages/ directory will be code split into its own JavaScript bundle during the build process.

https://nextjs.org/docs/migrating/from-react-router#code-splitting

확인해보니 메인페이지에서는 검색페이지와 관련된 코드를 불러오지 않고 메인페이지에 필요한 것만 불러오는 것을 확인할 수 있었다. (페이지를 추가적으로 작성하고나면 서버를 껐다켜야 정상적으로 작동했다.)

다이나믹 라우팅

url이 상황에 따라 변화는 다이나믹 라우팅 처리 또한 pages 디렉토리 하위에서 처리해주면 된다.

우선, 페이지 이동을 위해 만들어두었던 navigation 컴포넌트에 추가적인 코드를 작성해둔다.

// components/Navigation.tsx

const Navigation = () => {
  return (
    <header>
      <ul>
        // 생략...
        <li>
          <Link href="/post/first">
            <a>First Post</a>
          </Link>
        </li>
        <li>
          <Link href="/post/second">
            <a>Second Post</a>
          </Link>
        </li>
      </ul>
    </header>
  );
}

이제 pages 디렉토리 하위에 post라는 디렉토리를 만들고 그 하위에 [id].tsx 파일을 생성한다.

import { useRouter } from "next/router";

const Post = () => {
  const router = useRouter();
  const { id } = router.query;
  
  return (
    <div>
      <p>Post: {id}</p>
    </div>
  );
}

export default Post;

이렇게 작성하고 나면 /post/1, /post/abc, /post/first 와 같은 경로는 pages/post/[id].tsx에 매치되어 query object에 결과가 나오게 된다.
/post/second

{ "id": "second" }

쿼리 스트링을 사용한 케이스도 query object에 담기게 된다.
/post/abc?foo=bar

{ "foo": "bar", "id": "abc" }

다음은 네비게이션의 Second Post를 클릭했을 때 나오는 결과이다.

그렇다면 /post만 하였을 때는 어떻게 될까?

당연하게도 404에러가 발생하며 해결하려면 /pages/post에 index.tsx를 작성해주면 된다.

non-dynamic route는 dynamic route보다 우선시 되기 때문이다.

// pages/post/index.tsx

const Index = () => {
    return (
      <div>
        <p>Default 페이지</p>
      </div>
    );
}

export default Index;

Reference

좋은 웹페이지 즐겨찾기