7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Next.js】入門してみたまとめ ✍🏻

Last updated at Posted at 2023-06-18

Next.jsとは

スクリーンショット 2023-06-18 16.51.21.png

Vercel社が開発したReact開発のためのフレームワーク🚀
高速なWebアプリケーション作成のための様々な機能を提供しています。
ルーティングや開発環境などが簡単に構築、設定でき、SSR(Server Side Rendering)やSSG(Static Site Generation)、ISR(Incremental Static Regeneration)といったサーバー側のレンダリング機能がデフォルトで備えられてるところが特長です。

React
UIを構築するための機能を提供するライブラリ

Next.js
React開発のための機能を提供するフレームワーク

Next.jsの主な機能

  • 複数のレンダリング方法(SSR、SG、ISG)
  • ファイルベースルーティング(ダイナミックルート)
  • APIの作成(API Routes)
  • デベロッパーに優しい開発環境(ゼロコンフィグ)

プリレンダリングとは

プリレンダリングとは、サーバーサイドでページのHTMLを事前に生成し、レンダリングする機能です。
ブラウザへの初期表示速度や、検索エンジン最適化(SEO)を大きく向上させます。
Next.jsでは、このプリレンダリングを下記2つの方法で提供します。

SSG (Static Site Generation)

Static Site Generationの頭文字をとった造語で、静的生成を意味します。
プリレンダリングのタイミングはビルド時(next build)です。

SSR(Server Side Rendering)

Server Side Renderingの頭文字をとった造語で、サーバーサイドレンダリングという言葉の通り、
サーバー側でレンダリングしてくれます。

Next.jsのインストール

インストールにはいくつか方法がありますので、都度プロジェクトに合わせて行ってください。
下記は一例です。

create-next-app プロジェクト名
cd プロジェクト名
npm run dev
上記でローカルサーバーが立ち上がります。

ディレクトリ構成

上記などの方法でインストールが完了するとプロジェクトの雛形が作成されています。
インストール直後のデフォルトではルートディレクトリ配下に下記ディレクトリなどが配置されています。

/pages
pagesディレクトリ配下記載したコンポーネントファイルが一つのページに対応することになります。
pagesディレクトリにファイルを追加すれば、自動的にルーティングが作成されます。

pages/index.js → /
pages/about/index.js → /about

/styles
cssファイルを格納します。

/public
画像ファイルやフォントファイル、アイコンファイルなど静的ファイルを格納します。

デフォルトのままのフォルダ構成で開発しても問題ないが、主にpagesフォルダとstylesフォルダにコードを加えていくことになると思うので、ルートディレクトリにsrcフォルダを作成して、pagesフォルダ・stylesフォルダをsrcフォルダに格納して開発したりします。

Next.jsにおけるルーティングの方法

Next.jsの場合は、/pages内がルーディングの対象になり、ファイルまでのパスがそのままurlになります。
例えば/pages配下にindex.jsファイルを作成した場合、http://localhost:3000/などルートパスに対して作成したindex.js内の内容が返却されます。

ルーティングとは
URLでリクエストを送信した際に、どのプログラムを実行するかの紐付けです。

例1)
pages/
 └ index.js

pages/index.js
export default function Home() {
  return <h1>/pages/index.js</h1>;
}

npm run devでローカルサーバー立ち上げると下記内容がレンダリングされます。
スクリーンショット 2023-06-11 15.28.50.png

例2)
pages/
 └ index.js
 └ blog/
  └ index.js

pages/blog/index.js
export default function Blog() {
  return <h1>/blog/index.js</h1>;
}

http://localhost:3000/blogをブラウザurlに入力すると上記ファイルが返却されるので下記画面が表示されます。
スクリーンショット 2023-06-11 15.42.06.png

動的なルーティング

前項では、「/pages内がルーディングの対象になり、ファイルまでのパスがそのままurlになります。」と説明をしました。
ですが例えばブログページで考えた場合に、投稿するごとに増えるurlに対して、/pages/blog/1/pages/blog/2のようにファイルを作成していくわけではありません。
このようなケースの時に使用するのが、動的なルーディング、ダイナミックルーティングです💡
ダイナミックルーティングを用いることによって、/pages/blog/1の1の部分など、urlの一部を動的な値に変更することができ、jsファイルを一つだけ作成すればいいことになります。

例)
pages/
 └ index.js
 └ blog/
  └ [number].js ← [number]部分がダイナミックルーティングになり、この値がjs内で使用可能になる📌

pages/blog/[number].js
export default function number() {
  return <h1>blog/[number].js</h1>;
}

http://localhost:3000/blog/1http://localhost:3000/blog/2などのurlを指定すると[number].jsファイルの中身が返却されています。
スクリーンショット 2023-06-11 17.26.40.png

フォルダにもダイナミックルーティングを使用できます。

例)
pages/
 └ index.js
 └ blog/
  └ [number].js
 └ [name]/
  └ setting.js

http://localhost:3000/sato/settinghttp://localhost:3000/yamada/settingなどでアクセスしても同じようにsetting.jsの中身が返却され下記画面がレンダリングされます。
スクリーンショット 2023-06-11 17.32.49.png

ちなみに上記のようなディレクトリ構造で、http://localhost:3000/blog/settingにアクセスした場合、/pages/blog/[number].jsの中身が返却されます。
ダイナミックルーティングを行っている同階層に固定パスがあった場合は、固定パスが優先されるとのことです✍🏻

動的に変わるパスの値を取得する方法

動的に変わるパスを取得する方法は主に二つです。

  1. getServerSideProps()の使用
  2. ReactフックであるuseRouterの使用

getServerSideProps()

getServerSideProps()とはSSR(サーバーサイドレンダリング)時の、関数コンポーネントのpropsを定義する際に使用します。

例)

pages/[name]/setting.js
export default function Settinh({ hello }) {
  return <h1>{hello}</h1>;
}

export async function getServerSideProps() {
  return {
    props: {
      hello: "こんにちは",
    },
  };
}

上記、関数コンポーネントは下記のようにレンダリングされ、propsに設定した値が出力されています。
スクリーンショット 2023-06-17 8.09.49.png

このgetServerSideProps()は引数にcontextを取ることができ、そのcontextの一つのプロパティであるqueryの値に動的なパスを取得できます。

contextとは
getServerSideProps()に渡されるオブジェクトであり、以下のようなプロパティを持っています。

  • context.params: URL パラメータやダイナミックルーティングによって受け取ったパラメータが含まれるオブジェクトです。
  • context.query: クエリパラメータが含まれるオブジェクトです。
  • context.req: Node.js のリクエストオブジェクトです。ヘッダーや Cookie などの情報にアクセスできます。
  • context.res: Node.js のレスポンスオブジェクトです。レスポンスに関する情報を設定したり、リダイレクトを行ったりできます。

下記のようにcontext.queryをconsoleし、http://localhost:3000/test/settingにアクセスすると、query.nameプロパティに動的なパスが格納されていることがわかります。

例)

pages/[name]/setting.js
export default function Setting({ hello }) {
  return <h1>{hello}</h1>;
}

export async function getServerSideProps(context) {
  console.log(context.query); // → query: { name: 'test' }
  return {
    props: {
      hello: "こんにちは",
    },
  };
}

このcontext.querypropsとして渡すことによって動的なパスを関数コンポーネント内で使用できます🎉

例)

pages/[name]/setting.js
export default function Setting({ hello, query }) {
  return (
    <>
      <h1>{hello}</h1>
      <h2>{query.name}</h2>
    </>
  );
}

export async function getServerSideProps(context) {
  return {
    props: {
      hello: "こんにちは",
      query: context.query, // 動的パス情報をqueryプロップスに格納
    },
  };
}

http://localhost:3000/test/settingにアクセスすると下記レンダリングがされています。
スクリーンショット 2023-06-17 8.33.25.png

useRouterフック

動的パス取得のもう一つの方法としてuseRouterフックの使用も可能です。
useRouterとはNext.jsで提供されるReactフックの一つで現在のルートやURLパラメータ、クエリパラメータなどのプロパティを持つオブジェクトを返却する関数になります✍🏻
返却されるオブジェクトを格納する定数名はなんでもよいですが、慣例的にrouterとすることが多いと思います。
next/routerモジュールからインポートして使用します。
下記のようなコードで動的パスを取得し、レンダリングできます。

例)

pages/[name]/setting.js
import { useRouter } from "next/router";

export default function Setting() {
  const router = useRouter(); // `query.name`などのプロパティを持つオブジェクトの格納
  return (
    <>
      <h1>{router.query.name}</h1>
    </>
  );
}

useRouterを使って画面遷移させる方法

useRouterフックは様々なプロパティを持つオブジェクトを返却すると先述しました。
そのオブジェクトはプロパティだけではなく、様々なメソッドも含まれています。
その一つである'push()'は画面遷移させるメソッドです。
構文は下記のとおりです。
router.push("遷移先URL","urlに表示させたいurl",オプション)
第二引数以降は省略可能です。

例)

pages/[name]/setting.js
import { useRouter } from "next/router";
export default function Setting() {
  const router = useRouter();
  const clickHandler = () => {
    router.push("/"); // 引数に渡したurlに遷移する
  };
  return (
    <>
      <h1>{router.query.name}</h1>
      <button onClick={clickHandler}>トップへ</button>
    </>
  );
}

replaceメソッド

replace()というメソッドもあり、こちらも同様に画面遷移させるメソッドです。
基本的にpush()と同じような構文で使用できますが、push()と違って、履歴に追加せず画面処理を行います。
遷移後、ブラウザバックを押した際に、遷移元の前のページを開くような挙動になります。
他にも様々なメソッドがありますが、丁寧に解説された記事がありましたのでここでは省略します。

Linkを使った画面遷移

Linkコンポーネントを使用することで、リンクへ遷移させることもできます。

例)

pages/index.js
import Link from "next/link"; // Linkコンポーネントimport

export default function Home() {
  return (
    <>
      <h1>Home</h1>
      <Link href="/blog/1">
        <a>Blogへ</a>
      </Link>
    </>
  );
}

router.push()と同様に、as属性を用いることによって、ブラウザのURLバーに表示されるパスを指定もできます。

pages/index.js
import Link from "next/link"; 

export default function Home() {
  return (
    <>
      <h1>Home</h1>
      <Link href="/blog/1" as="test-url">
        <a>Blogへ</a>
      </Link>
    </>
  );
}

href属性はオブジェクト形式で記述も可能で、クエリーパラメーターの指定もできます。
下記のようなオブジェクトを渡せば「Blogへ」リンククリックすると/blog/1?key=valueへ遷移します。

pages/index.js
import Link from "next/link";

export default function Home() {
  return (
    <>
      <h1>Home</h1>
      <Link
        href={{
          pathname: "/blog/1",
          query: {
            key: "value",
          },
        }}
      >
        <a>Blogへ</a>
      </Link>
    </>
  );
}

ちなみに<a href="/blog/1">Blogへ</a>のように普通にaタグも使えますが、Linkコンポーネントを使用した遷移と違ってリロードが発生する画面遷移になります📡

シングルコンポーネントで複数画面を作成する方法

router.push()でクエリパラメーターを受け渡しして、一つのコンポーネントでも複数ページとして扱うこともできます。

例)

pages/
 └ multipage/
  └ index.js

/pages/multipage/index.js
import { useRouter } from "next/router";

const MultiPage = () => {
  const router = useRouter();
  const step = router.query.step ?? "0"; // null合体演算子
  const goToStep = (_step, asPath) => {
    router.push(`/multipage?step=${_step}`, asPath);
  };
  return (
    <div>
      {step === "0" && (
        <>
          <h3>Step: {step}</h3>
          <button onClick={() => goToStep(1, "/personal")}>Next Step →</button>
        </>
      )}
      {step === "1" && (
        <>
          <h3>Step: {step}</h3>
          <button onClick={() => goToStep(2, "/confirm")}>Next Step →</button>
        </>
      )}
      {step === "2" && (
        <>
          <h3>Step: {step}</h3>
          <button onClick={() => goToStep(0, "/multipage")}>Done</button>
        </>
      )}
    </div>
  );
};

export default MultiPage;

上記コンポーネントでhttp://localhost:3000/multipageにアクセスすると下記のように、ボタンクリックで画面が変化し、urlも設定したダミーurl、/multipage/personal/confirmに変化していくコンポーネントが作成されます。
multipage.gif

const step = router.query.step ?? "0";でクエリパラメーターを取得し、stap定数に代入しています。
jsx部分で、そのstep定数に格納された値によって、表示を切り替えている形です。

rewrites()の設定

上記で作成したmultipageコンポーネントではダミーurlを設定してシングルコンポーネントで複数画面を作成していますが、ブラウザで直接ダミーurlを入力した場合、ダミーurlですので404ページが開かれます。

http://localhost:3000/personalをブラウザurlに直接入力
スクリーンショット 2023-06-18 15.36.43.png

そこで、ダミーurlが直接入力された場合でも、うまく動作させるためにリライトという仕組みを用います。
next.config.jsにリライト設定を追加します。

react-guide-material/17_nextjs_p1/start/next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
+  async rewrites() {
+    return [
+     {
+        source: "/personal",
+        destination: "/multipage?step=1",
+      },
+      {
+        source: "/confirm",
+        destination: "/multipage?step=2",
+      },
+    ];
+  },
};

module.exports = nextConfig;

sourceのvalueに設定されたパスの入力があった場合に、destinationのvalueに設定されたurlに紐づくコンポーネントが実行されます📌
ローカルサーバーを一度閉じてから再度立ち上げて、http://localhost:3000/personalをブラウザurlに直接入力してみると今度はちゃんと表示されました!

head内にタグを挿入する方法

Next.jsで標準に提供されているコンポーネントでHeadコンポーネントというものがあります。
Headコンポーネントとはその名の通り、headタグ内に何らかのタグを挿入する際に使用します。

例)

/pages/index.js
import Head from "next/head"; // Headコンポーネントのimport

export default function Home() {
  return (
    <>
      <Head>
        <title>テスト</title>
      </Head>
      <h1>Home</h1>
    </>
  );
}

上記コンポーネントを作成し、http://localhost:3000/にアクセスすると、headタグ内に設定したtitleが挿入されています。
このようにHeadコンポーネントを用いれば、そのコンポーネント固有のheadタグを挿入することができます。
スクリーンショット 2023-06-18 16.44.06.png

まとめ

今回はNext.jsの入門的な内容をまとめました✏️
次回はNextの強力な機能となるSGやSSRについてまとめたいと思います!🫡

7
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
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?