Next.jsとは
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
export default function Home() {
return <h1>/pages/index.js</h1>;
}
npm run dev
でローカルサーバー立ち上げると下記内容がレンダリングされます。
例2)
pages/
└ index.js
└ blog/
└ index.js
export default function Blog() {
return <h1>/blog/index.js</h1>;
}
http://localhost:3000/blog
をブラウザurlに入力すると上記ファイルが返却されるので下記画面が表示されます。
動的なルーティング
前項では、「/pages内がルーディングの対象になり、ファイルまでのパスがそのままurlになります。」と説明をしました。
ですが例えばブログページで考えた場合に、投稿するごとに増えるurlに対して、/pages/blog/1
、/pages/blog/2
のようにファイルを作成していくわけではありません。
このようなケースの時に使用するのが、動的なルーディング、ダイナミックルーティングです💡
ダイナミックルーティングを用いることによって、/pages/blog/1
の1の部分など、urlの一部を動的な値に変更することができ、jsファイルを一つだけ作成すればいいことになります。
例)
pages/
└ index.js
└ blog/
└ [number].js ← [number]部分がダイナミックルーティングになり、この値がjs内で使用可能になる📌
export default function number() {
return <h1>blog/[number].js</h1>;
}
http://localhost:3000/blog/1
、http://localhost:3000/blog/2
などのurlを指定すると[number].js
ファイルの中身が返却されています。
フォルダにもダイナミックルーティングを使用できます。
例)
pages/
└ index.js
└ blog/
└ [number].js
└ [name]/
└ setting.js
http://localhost:3000/sato/setting
、http://localhost:3000/yamada/setting
などでアクセスしても同じようにsetting.js
の中身が返却され下記画面がレンダリングされます。
ちなみに上記のようなディレクトリ構造で、http://localhost:3000/blog/setting
にアクセスした場合、/pages/blog/[number].js
の中身が返却されます。
ダイナミックルーティングを行っている同階層に固定パスがあった場合は、固定パスが優先されるとのことです✍🏻
動的に変わるパスの値を取得する方法
動的に変わるパスを取得する方法は主に二つです。
-
getServerSideProps()
の使用 - Reactフックである
useRouter
の使用
getServerSideProps()
getServerSideProps()
とはSSR(サーバーサイドレンダリング)時の、関数コンポーネントのprops
を定義する際に使用します。
例)
export default function Settinh({ hello }) {
return <h1>{hello}</h1>;
}
export async function getServerSideProps() {
return {
props: {
hello: "こんにちは",
},
};
}
上記、関数コンポーネントは下記のようにレンダリングされ、props
に設定した値が出力されています。
この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
プロパティに動的なパスが格納されていることがわかります。
例)
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.query
をprops
として渡すことによって動的なパスを関数コンポーネント内で使用できます🎉
例)
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
にアクセスすると下記レンダリングがされています。
useRouter
フック
動的パス取得のもう一つの方法としてuseRouter
フックの使用も可能です。
useRouter
とはNext.jsで提供されるReactフックの一つで現在のルートやURLパラメータ、クエリパラメータなどのプロパティを持つオブジェクトを返却する関数になります✍🏻
返却されるオブジェクトを格納する定数名はなんでもよいですが、慣例的にrouter
とすることが多いと思います。
next/router
モジュールからインポートして使用します。
下記のようなコードで動的パスを取得し、レンダリングできます。
例)
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",オプション)
第二引数以降は省略可能です。
例)
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コンポーネントを使用することで、リンクへ遷移させることもできます。
例)
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バーに表示されるパスを指定もできます。
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
へ遷移します。
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
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
に変化していくコンポーネントが作成されます。
const step = router.query.step ?? "0";
でクエリパラメーターを取得し、stap定数に代入しています。
jsx部分で、そのstep
定数に格納された値によって、表示を切り替えている形です。
rewrites()
の設定
上記で作成したmultipage
コンポーネントではダミーurlを設定してシングルコンポーネントで複数画面を作成していますが、ブラウザで直接ダミーurlを入力した場合、ダミーurlですので404ページが開かれます。
http://localhost:3000/personal
をブラウザurlに直接入力
そこで、ダミーurlが直接入力された場合でも、うまく動作させるためにリライトという仕組みを用います。
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タグ内に何らかのタグを挿入する際に使用します。
例)
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タグを挿入することができます。
まとめ
今回はNext.jsの入門的な内容をまとめました✏️
次回はNextの強力な機能となるSGやSSRについてまとめたいと思います!🫡