[A-00210] Journey to Frontend(Next.js)
フロントエンドが苦手なのでこの記事で練習&ポートフォリオを作成していきます。
・簡単なSPAを作ってみる
今回は学習記事に沿ってnpmではなくyarnを使ってビルドします。
下記コマンドを実行してyarn導入とNext.js/React, typescriptを導入してください。
npm -g i yarn
yarn add next react react-dom
yarn add -D typescript @types/node @types/react
package.jsonにスクリプトを追加しておく
{
"scripts": {
"dev": "next",
"start": "next start",
"build": "next build",
"export": "next export"
},
"dependencies": {
"next": "^14.2.5",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/node": "^20.14.12",
"@types/react": "^18.3.3",
"typescript": "^5.5.4"
}
}
directoryを作成して実行ファイルも作成する
mkdir src && mkdir src/pages
touch src/pages/index.tsx
const Page = () => <div>Hello SPA!</div>;
export default Page;
下記のコマンドでhttpサーバーを起動します。
yarn next
下記の画面が表示されます。

上記のsrc/pagesフォルダ配下に置くことで動くのがPage Routerなるものらしいです。
現在はApp Routerが主流ですが、一旦学習のため、Page Routerの学習を進めます。
基本的にpagesディレクトリさえあればOKのようです。上記はsrc/pagesとしましたが、直下に./pagesでもOKです。
・Dynamic Routingについて
ファイル名を動的な値にして、リクエストURLで任意の値で受信し、表示します。
ディレクトリを作成、ファイルを作成します。
mkdir pages/blogs
touch pages/blogs/[number].tsx
import { useRouter } from "next/router"
export default function Page() {
const router = useRouter();
return (
<p>
Post: {router.query.number}
</p>
)
}
npm run devで起動し、下記のURLを打ち込むと、URLのパラメータ部分がそのままページに表示されます。

・(豆知識)PageRouterとApp Routerについて
page routerを使用する場合、pagesディレクトリ配下にファイルを作成します。
app routerを使用する場合、appディレクトリ配下にファイルを作成します。
これら二つが存在するとconflictを起こして起動に失敗します。
下記のようなディレクトリ構成でサーバーを起動させます。

pages/index.tsxとapp/page.tsxがconflictします。下記のようなエラー画面が表示されます。

・App Routerを使ってみる
app routerを使うにはappディレクトリにファイルを作成していきます。
下記のコマンドでプロジェクト配下にライブラリを作成します。
npm install next@latest react@latest react-dom@latest typescript@latest @types/react @types/node
ディレクトリを作成します。
mkdir app
cd app
touch page.tsx
import React from "react";
export default function Page() {
return <h1>Hello, App Router!</h1>
}
npm run dev
下記の画面が表示されます。

・Page, Layoutについて学ぶ
ディレクトリ構成とURLは密接に関係しています。
appディレクトリ直下のpage.tsx(or index.tsx)ならデフォルトURL(URLパス無し)で表示されます。
app/dashboadディレクトリを作成するとURLは[/dashboad]になります。

import React from "react";
export default function Page() {
return <h1>Here is inside of Dashboad.</h1>
}
実行すると下記のようになります。

layoutについて、next.jsを起動すると自動でappディレクトリ直下にlayout.tsxを作成してくれます。
これをrootLayoutというようです。app/dashboardに作成したlayout.tsxはこのrootlayoutを継承します。
下記のようなファイルを作成して実行します。
export const metadata = {
title: 'Next.js',
description: 'Generated by Next.js',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
export default function DashboardLayout({
children,
} : {
children: React.ReactNode
}) {
return (
<section>
{/* Include shared UI here */}
<nav>This is Navigation</nav>
{children}
</section>
)
}
表示したら下記のようになります。

・Metadataについて
titleなどのメタデータの取り扱いは下記のようになる
import React from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Next.js",
}
export default function Page() {
return <h1>Hello, App Router!</h1>
}
・Linkについて
app-routerによる別ページへのルーティングをLinkを使って行う際に下記ようなコードになる.補足だが複数のHTMLタグをリターンしたい時はJSXタグを用いる
import React from "react";
import { Metadata } from "next";
import Link from "next/link";
export const metadata: Metadata = {
title: "Next.js",
}
export default function Page() {
return (
<>
<h1>Hello, App Router!</h1>
<Link href="/dashboard">GotoDashboard</Link>
</>
)
}


次にNavigationを作ってみます。三項演算が登場しますが、あまりよくわかってないのでLinkの使い方として一例程度にみてください。
'use client'
import { usePathname } from "next/navigation"
import Link from "next/link"
export default function Links() {
const pathname = usePathname()
return (
<>
<p>Current pathname: {pathname}</p>
<nav>
<ul>
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Home
</Link>
</li>
<li>
<Link className={`link ${pathname === '/about' ? 'active' : ''}`} href="/about">
About
</Link>
</li>
</ul>
</nav>
</>
)
}


・useRouterを使ってみる
useRouterを使って適当なページにhookしてみます。ちなみにnext/routerのuseRouterは古いらしいので間違えずにnext/navigationパッケージのuseRouterを使うことに注意してください。useRouterはクライアントサイドで動作するので[use client]を付けます。
'use client'
import { useRouter } from "next/navigation"
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/about')}>
About
</button>
)
}


・Appendix
参考サイトはこちら
https://next-blog.croud.jp/contents/pFIUJ2UOv4qkdvKbgl5O
https://qiita.com/hiroki-yama-1118/items/b3388c5dcb155e2e367d
コメントを残す