LoginSignup
6
2

More than 1 year has passed since last update.

Routing

Dynamic Routesの前にNext.jsのルーティングについて簡単に説明します。

Next.jsはプロジェクト直下、もしくはsrcディレクトリ配下のpagesディレクトリに格納されているファイルを自動的にルーティングしてくれます。

例えば、下記のディレクトリ構成があったとします。

src/
|- pages/
    |- articles/
    |  |- index.tsx     ①
    |- admin/
       |- articles/
           |- index.tsx ②

本ディレクトリ構成のプロジェクトをデプロイしたウェブサイトでは、https://example.com/articlesにアクセスすれば、①のページがレスポンスされます。その他、https://example.com/admin/articlesにアクセスすれば、③のページがレスポンスされます。

このようにNext.jsではpages配下にディレクトリ構成に基づいて、自動的にルーティングを実現してくれます。

Dynamic Routes

事前に用意できるファイルについては自動的にNext.js側でルーティングしてくれることがわかりました。
それでは事前に用意できないような投稿した記事の詳細画面の場合はどのようにしたら良いでしょうか。

その課題を解決する手段としてNext.jsではDynamic Routesが用意されています。

src/
|- pages/
    |- articles/
    |  |- index.tsx
    |  |- [id].tsx ☆
    |- admin/
       |- articles/
           |- index.tsx

上記ディレクトリ構成の[id].tsxのようにNext.jsでは角括弧付きでファイルを格納することで動的なルーティングを実現します。

上記がデプロイされたウェブサイトの場合、https://example.com/articles/1https://example.com/articles/aiueo[id].tsxをページとしてレスポンスします。

ちなみに[id].tsxでは指定されたパス(=id)の記事の詳細をレスポンスしたいので、下記のコードのようにrouter.queryでパスを取得して利用します。

import { useRouter } from 'next/router';
import { ArticleDetail } from '~/components/atoms/articleDetail';

const ArticleDetails: NextPage = async () => {
  const router = useRouter();
  const { id } = router.query;

  const article = await fetch(`/article/${id}`).then((res) => res.json());

  return <ArticleDetail article={article} />;
};

export default ArticleDetails;

getStaticPaths及びgetStaticPropsを利用する方法

Next.jsではgetStaticPropsを利用することでSSGを実現できます。

単純にパスを指定可能なファイルについてはgetStaticPropsを用いて下記のように記述することでSSGを実現します。

src/pages/article/index.tsx

import { NextPage } from 'next';
import { ArticleCard } from '~/components/atoms/articleCard';
import { getAllArticle } from '~/lib/article';

interface Article {
  // オブジェクトの型指定
}

type Props = {
  articles: Article[];
};

const ArticleList: NextPage<Props> = ({ articles }) => {
  return (
      <div>
          {articles.map((article) => (
            <ArticleCard key={article.id} article={article} />
          ))}
      </div>
  );
};

export const getStaticProps = async() => {
  const articles: Articles[] = await getAllArticle();

  return {
    props: { articles },
    revalidate: 3,
  };
}

export default ArticleList;

ビルド時にgetStaticPropsは取得したデータをpropsとして返却します。返却されたpropsはページが受け取って、そのデータを元に静的サイトを生成します。

また、propsと同時に返却しているrevalidateについてはこちらの記事を参考にしてください。

次に、事前にパスを指定できない記事詳細ページについてはgetStaticPathsを用いて下記のように記述することでSSGを実現します。

src/pages/article/[id].tsx

import { useRouter } from 'next/router';
import { NextPage } from 'next';
import { ArticleDetail } from '~/components/atoms/articleDetail';
import { ErrorPage } from '~/components/general'
import { getAllArticleId, getArticleById } from '~/lib/article';

interface Article {
  // オブジェクトの型指定
}

type Props = {
  article: Article;
};

const ArticleDetail: NextPage<Props> = ({ article }) => {
  const router = useRouter();

  // getStaticPropsでまだデータ取得できていない場合にrouter.isFallbackがtrue
  if (router.isFallback) return <div>Loading...</div>;

  // データが存在しない場合
  if(!article) return <ErrorPage code={404}/>;

  return (
    <div>
      <ArticleDetail article={article}/>
    </div>
  );
}

export const getStaticPaths = () => {
  const paths = await getAllArticleId();

  return {
    paths,
    fallback: true,
  };
}

export const getStaticProps = (paths: { params: { id: number } }) => {
  const article = await getArticleById(paths.params.id);

  return {
    props: {
      article,
    },
    revalidate: 3,
  };
}

export default ArticleDetail;

このようにgetStaticPropsとは別にgetStaticPathsを定義します。

ビルド時にgetStaticPathsはパスとなるidを取得してpathsとして返却します。

返却されたpathsに1から10までのidが含まれていた場合、1.tsx2.tsxのように[id]に1から10が割り当てられたファイルが生成されます。

1.tsxの場合はidとしてがgetStaticPropsに引数として渡されます。
その後は前項に記載したようにgetStaticPropsは取得したデータをpropsとして返却します。返却されたpropsはページが受け取って、そのデータを元に静的サイトを生成します。

このようにしてSSGの場合もDynamic Routesを実現します。

ちなみに何もしなければ、ビルド後に追加されたidの詳細ページを追加できません。
getStaticPathsの返却する値にfallbackを追加して、trueもしくは'blocking'を指定することでビルドされていないパスに指定された場合に再ビルドさせることができます。

fallbackの詳細については公式サイトをご参照ください。

最後に

記事の内容がわかりづらければ、ご指摘いただけますと幸いです。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2