[Next.js] Dynamic Routes

Dynamic Routes


기본개념

  • 각 파일에 대한 동적경로를 지원

사용 라이브러리

Render Markdown

  • 설치
npm install remark remark-html

Formatting the Date

  • 설치
npm install date-fns
  • /components/date.js
import { parseISO, format } from "date-fns";

export default function Date({ dateString }) {
  const date = parseISO(dateString);

   format은 변경 가능
  return <time dateTime={dateString}>{format(date, "LLLL d, yyyy")}</time>;
}

코드 설명

posts.js

import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import remark from 'remark'
import html from 'remark-html'

  파일의 이름만 id값으로 뽑아 배열로 반환
export function getAllPostIds() {
  const fileNames = fs.readdirSync(postsDirectory)

   map()함수: 배열의 특정 값만 뽑아서 리스트로 반환
  return fileNames.map(fileName => {
    return {
      params: {
        id: fileName.replace(/\.md$/, '')
      }
    }
  })
}

 id, html로 변환된 마크다운, matterResult.data(title, date 포함) 리턴
export async function getPostData(id) {
  const fullPath = path.join(postsDirectory, `${id}.md`)
  const fileContents = fs.readFileSync(fullPath, 'utf8')

   gray-matter를 사용해서 metadata section 부분을 파싱
  const matterResult = matter(fileContents)

   remark를 사용해서 마크다운 언어의 콘텐트를 html로 변환
  const processedContent = await remark()
    .use(html)
    .process(matterResult.content)
  const contentHtml = processedContent.toString()

  // Combine the data with the id and contentHtml
  return {
    id,
    contentHtml,
    ...matterResult.data
  }
}

[id].js

  • Next.js에서 dynamic routes를 사용하기 위해 파일명을 []로 감싼다.
  • 각 파일(여기서는 md파일)을 render하는 페이지
import Layout from '../../components/layout'
import { getAllPostIds, getPostData } from '../../lib/posts'
import Head from 'next/head'
import Date from '../../components/date'
import utilStyles from '../../styles/utils.module.css'

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

      <article>
        <h1 className={utilStyles.headingXl}>{postData.title}</h1>
        <div className={utilStyles.lightText}>
          <Date dateString={postData.date} />
        </div>
        <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
      </article>
    </Layout>
  );
}

export async function getStaticPaths() {
  const paths = getAllPostIds();
  return {
    paths,
    fallback: false,
  }
}

  build time시 가장 먼저 실행됨
export async function getStaticProps({ params }) {

   import한 posts.js의 getPostData() 호출
   id, html로 변환된 마크다운, matterResult.data(title, date 포함) 받음
  const postData = await getPostData(params.id);
  return {
    props: {
      postData,
    },
  };
}

index.js

<section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
  <h2 className={utilStyles.headingLg}>Blog</h2>
  <ul className={utilStyles.list}>
    {allPostsData.map(({ id, date, title }) => (
      <li className={utilStyles.listItem} key={id}>

         posts/[id].js를 호출
         파일명이 id 값이 되며 dynamic routes가 생성되어 있어 해당 파일의 페이지가 호출되는 방식
        <Link href={`/posts/${id}`}>
          {title}
        </Link>
        <br />
        <small className={utilStyles.lightText}>
          <Date dateString={date} />
        </small>
      </li>
    ))}
  </ul>
</section>

links

social