Next.js

[Next.js] 라우팅 이론과 실습

JeanneLee57 2023. 5. 8. 22:20

 

 

Next.js의 라우팅 방식에 대해 알아보고 실습으로 구현해보자.

 

라우팅 알아보기

라우트 정의

app 디렉토리 내에서 폴더를 생성하면 폴더명으로 라우트가 정의된다. 폴더 내에 새로운 폴더를 만들면 하위 경로를 만들 수 있다.

폴더 내에 page.js 파일을 만들면 해당 라우트 url의 페이지가 된다.

 

페이지와 레이아웃

페이지란 하나의 라우트를 통해서만 접근할 수 있는 고유한 UI를 말한다. page.js 파일에서 컴포넌트를 export하면 페이지를 정의할 수 있다.

레이아웃이란 여러 페이지에서 공유되는 공통된 UI를 말한다. 내브바 같은 것을 삽입할 때 유용하다. 사용자가 페이지를 이동해도 공통의 레이아웃은 재렌더링되지 않고, 상태를 보존한다. 레이아웃은 layout.js파일에서 컴포넌트를 export해서 만들 수 있다. 컴포넌트는 렌더링 중에 자식 레이아웃 또는 자식 페이지로 채워질 자식 prop을 받아야 한다.

 

경로 탐색

경로 이동 및 탐색은 두 가지를 통해서 구현할 수 있다. 하나는 <Link> 컴포넌트이고, 다른 하나는 useRouter() 훅이다.

<Link> 컴포넌트는 html의 <a> 태그와 비슷한 역할을 하면서도 프리페칭을 구현하고 클라이언트 사이드 렌더링을 지원한다. <Link> 컴포넌트의 프리페칭을 원하지 않는다면 prefetch={false}로 속성을 설정하면 된다.

 

useRouter() 훅은 클라이언트 컴포넌트에서만 사용 가능하다. 프로그램적으로 라우트를 변경할 수 있도록 해준다.

useRouter에는 여러 메서드도 포함돼 있다. router.back()은 뒤로 가기, router.forward()는 앞으로 가기, router.refresh()는 새로고침, router.prefetch()는 다음 페이지를 미리 로드할 수 있게 해준다.

 

관련된 훅들도 함께 살펴보면 

usePathname()은 현재 url을 출력해주고, useSearchParams() 서치파라미터(쿼리스트링)를 출력한다. useParams()는 유저가 [dynamic route]에 입력한 것을 출력한다.

 

라우트 그룹

라우트 그룹은 여러 라우트를 그룹으로 묶되 경로에는 영향을 주지 않는다. 폴더명을 소괄호'()'로 묶어서 만든다. 여러 라우트를 묶어서 공통의 레이아웃을 제공하면서도 별도의 url은 생성하지 않고 싶을 때 사용할 수 있다. 라우트 그룹을 사용해 여러 개의 루트 레이아웃을 만들 수도 있다.

 

동적 라우팅

정확한 세그먼트 이름을 미리 알기 어렵고 동적인 데이터를 받아서 라우트를 정의하려 할 때 동적 라우팅을 사용할 수 있다. 폴더명을 대괄호'[]'로 묶으면 동적 세그먼트를 생성한다. 글 번호나 유저 번호를 받아서 라우팅을 할 때 유용하다.

 

라우팅 실습

간단한 게시판 페이지를 만들어 글 고유 id에 따라서 라우트를 생성하고 게시글 페이지로 이동할 수 있게 해보자.

몽고DB 서버에 글 목록의 더미 데이터를 저장해 두었다.

 

폴더와 파일은 위와 같이 구성돼 있다. list 폴더가 /list 페이지로 연결되고, /detail/[postId]는 동적 라우팅을 구현해 글 id를 받아와 표시할 수 있도록 했다. 루트 경로에 들어 있는 layout.js로 내브바를 생성했다.

 

import { connectDB } from "@/util/database";
import Link from "next/link";

export default async function List() {
  //몽고DB 문법
  const client = await connectDB;
  const db = client.db("forum");
  let result = await db.collection("post").find().toArray();

  //글 리스트를 받아와 표시한다.
  return (
    <div className="list-bg">
      {result.map((post) => {
        return (
          <div className="list-item">
            <Link href={`/detail/${post._id}`}><h4>{post.title}</h4></Link>
            <p>{post.content}</p>
          </div>
        );
      })}
    </div>
  );
}

list 폴더의 page.js 파일이다. 서버로부터 데이터를 받아와 화면에 표시하는 간단한 구성이다.

<Link> 컴포넌트를 통해서 각각의 글로 이동할 수 있다.

 

import { ObjectId } from "mongodb";
import { connectDB } from "@/util/database.js";

//props로 url의 정보를 받는다.
export default async function Detail(props) {
  let db = (await connectDB).db("forum");
  let result = await db
    //몽고DB 문법
    .collection("post")
    .findOne({ _id: new ObjectId(props.params.postId) });

  return (
    <div>
      <h4>{result.title}</h4>
      <p>{result.content}</p>
    </div>
  );
}

detail/[postId]의 page.js 파일이다. props를 통해서 url에 접근할 수 있다!

url에서 글 id를 받아오면 서버에서 받아온 글 목록 중에서 id와 일치하는 것을 찾아서 표시한다.

 

import './globals.css'
import { Inter } from 'next/font/google'
import Link from 'next/link'

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({ children }) {
  return (
    <html lang="en">
    //여기가 핵심
      <body className={inter.className}><div className="navbar"> 
  <Link href="/" className="logo">Kuromiforum</Link> 
  <Link href="/list">List</Link> 
</div>  {children}</body>
    </html>
  )
}

layout.js의 내브바는 위와 같이 만들었다. Kuromiforum을 누르면 루트 경로로 이동, List를 누르면 글 목록으로 이동한다. 마찬가지로 <Link> 컴포넌트를 사용했다.

 

작고 귀여운... 결과물..🥲

이렇게 라우팅도 잘 되는 것을 확인할 수 있다.

Next.js 라우팅 실습 유익하고 재밌었다!

 

 


참고 자료

 

Next.js 공식 문서

https://nextjs.org/

 

코딩애플: Next.js로 웹서비스 만들기

https://codingapple.com/course/next-js/