1. Next.jsとは
Next.jsは、Reactベースのフレームワークで、高速で効率的なウェブアプリケーション開発を可能にします。
// Next.jsの基本的な構造
my-app/
├── pages/
│ └── index.js
├── public/
├── styles/
└── package.json
この構造が、Next.jsプロジェクトの基本となります。
2. Next.jsの特徴
Next.jsには以下のような特徴があります:
- サーバーサイドレンダリング(SSR)
- 静的サイト生成(SSG)
- ファイルベースのルーティング
- APIルート
// pages/index.js (SSRの例)
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/data')
const data = await res.json()
return { props: { data } }
}
export default function Home({ data }) {
return <div>{data.title}</div>
}
このコードは、サーバーサイドでデータをフェッチし、それをページコンポーネントに渡す例です。
3. 開発環境のセットアップ
Next.jsプロジェクトを始めるには、以下のコマンドを実行します:
npx create-next-app@latest my-blog
cd my-blog
npm run dev
これにより、新しいNext.jsプロジェクトが作成され、開発サーバーが起動します。
4. ページの作成
Next.jsでは、pages
ディレクトリ内のファイルが自動的にルートになります。
// pages/index.js
export default function Home() {
return <h1>ようこそ、Next.jsブログへ!</h1>
}
このコードで、トップページが作成されます。
5. ルーティング
Next.jsは、ファイルベースのルーティングを採用しています。
// pages/posts/[id].js
import { useRouter } from 'next/router'
export default function Post() {
const router = useRouter()
const { id } = router.query
return <p>ポストID: {id}</p>
}
この例では、動的ルーティングを使用して、URLパラメータを取得しています。
6. レイアウトの作成
共通のレイアウトを作成することで、コードの再利用性が高まります。
// components/Layout.js
export default function Layout({ children }) {
return (
<div>
<header>ヘッダー</header>
<main>{children}</main>
<footer>フッター</footer>
</div>
)
}
// pages/_app.js
import Layout from '../components/Layout'
function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
export default MyApp
この設定により、全てのページに共通のレイアウトが適用されます。
7. スタイリング
Next.jsは、CSSモジュールをサポートしています。
// styles/Home.module.css
.title {
color: blue;
font-size: 24px;
}
// pages/index.js
import styles from '../styles/Home.module.css'
export default function Home() {
return <h1 className={styles.title}>スタイリングの例</h1>
}
このように、コンポーネント固有のスタイルを簡単に適用できます。
8. 画像の最適化
Next.jsのImage
コンポーネントを使用すると、自動的に画像が最適化されます。
import Image from 'next/image'
export default function Avatar() {
return <Image src="/avatar.png" alt="アバター" width={50} height={50} />
}
このコードは、画像の遅延読み込みや適切なサイズ変更を自動的に行います。
9. APIルート
Next.jsでは、サーバーレスAPIを簡単に作成できます。
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'こんにちは!' })
}
このAPIは/api/hello
でアクセス可能になります。
10. データフェッチング
Next.jsには、データフェッチングのための特別な関数があります。
// pages/index.js
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts')
const posts = await res.json()
return {
props: {
posts,
},
}
}
export default function Home({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
この例では、ビルド時にデータをフェッチし、ページコンポーネントにpropsとして渡しています。
11. 動的ルーティング
動的ルーティングを使用すると、パラメータに基づいてページを生成できます。
// pages/posts/[id].js
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts')
const posts = await res.json()
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}))
return { paths, fallback: false }
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://api.example.com/posts/${params.id}`)
const post = await res.json()
return { props: { post } }
}
export default function Post({ post }) {
return <h1>{post.title}</h1>
}
この例では、全ての可能なパスを生成し、各パスに対応するデータをフェッチしています。
12. SEO対策
Next.jsでは、next/head
を使用してメタタグを簡単に設定できます。
import Head from 'next/head'
export default function Page() {
return (
<>
<Head>
<title>ページタイトル</title>
<meta name="description" content="ページの説明" />
</Head>
<h1>ページコンテンツ</h1>
</>
)
}
これにより、各ページに適切なメタ情報を設定し、SEO対策を行うことができます。
13. パフォーマンス最適化
Next.jsには、パフォーマンス最適化のための機能が多数あります。
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('../components/heavy-component'))
export default function Home() {
return (
<div>
<h1>ホーム</h1>
<DynamicComponent />
</div>
)
}
この例では、動的インポートを使用して、必要な時にのみコンポーネントを読み込んでいます。
14. 認証の実装
Next.jsでの認証実装は、通常、APIルートとクライアントサイドの状態管理を組み合わせて行います。
// pages/api/login.js
import { sign } from 'jsonwebtoken'
export default function handler(req, res) {
const { username, password } = req.body
if (username === 'admin' && password === 'password') {
const token = sign({ username }, process.env.JWT_SECRET)
res.status(200).json({ token })
} else {
res.status(401).json({ message: '認証失敗' })
}
}
// pages/login.js
import { useState } from 'react'
import { useRouter } from 'next/router'
export default function Login() {
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const router = useRouter()
const handleSubmit = async (e) => {
e.preventDefault()
const res = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
})
if (res.ok) {
const { token } = await res.json()
localStorage.setItem('token', token)
router.push('/dashboard')
}
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">ログイン</button>
</form>
)
}
この例では、簡単なログイン機能を実装しています。実際のアプリケーションでは、より堅牢な認証システムが必要です。
15. テスト
Next.jsアプリケーションのテストには、Jest和Reactテスティングライブラリを使用できます。
// __tests__/index.test.js
import { render, screen } from '@testing-library/react'
import Home from '../pages/index'
describe('Home', () => {
it('renders a heading', () => {
render(<Home />)
const heading = screen.getByRole('heading', {
name: /welcome to next\.js!/i,
})
expect(heading).toBeInTheDocument()
})
})
このテストは、ホームページに特定の見出しが表示されることを確認します。
16. デプロイ
Next.jsアプリケーションは、Vercelに簡単にデプロイできます。
npm install -g vercel
vercel
これらのコマンドを実行すると、アプリケーションがVercelにデプロイされます。
17. 国際化対応
Next.jsは、組み込みの国際化サポートを提供しています。
// next.config.js
module.exports = {
i18n: {
locales: ['en', 'ja'],
defaultLocale: 'en',
},
}
// pages/index.js
import { useRouter } from 'next/router'
export default function Home() {
const { locale } = useRouter()
return <h1>{locale === 'en' ? 'Welcome' : 'ようこそ'}</h1>
}
この設定により、/
と/ja
の両方のルートが生成されます。
18. PWA対応
Next.jsアプリケーションをPWA(Progressive Web App)にするには、next-pwa
パッケージを使用します。
// next.config.js
const withPWA = require('next-pwa')
module.exports = withPWA({
pwa: {
dest: 'public',
},
})
この設定により、アプリケーションがオフラインでも動作するようになります。
19. TypeScriptの導入
Next.jsはTypeScriptを標準でサポートしています。
// pages/index.tsx
import { GetStaticProps, NextPage } from 'next'
interface Props {
title: string
}
const Home: NextPage<Props> = ({ title }) => {
return <h1>{title}</h1>
}
export const getStaticProps: GetStaticProps = async () => {
return { props: { title: 'Welcome to Next.js!' } }
}
export default Home
このコードは、TypeScriptを使用してページコンポーネントとデータフェッチング関数を定義しています。
20. 実践的なブログ作成例
最後に、これまでの知識を活用して、簡単なブログアプリケーションを作成してみましょう。
// pages/index.js
import Link from 'next/link'
export default function Home({ posts }) {
return (
<div>
<h1>ブログ記事一覧</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/posts/${post.id}`}>
<a>{post.title}</a>
</Link>
</li>
))}
</ul>
</div>
)
}
export async function getStaticProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts')
const posts = await res.json()
return {
props: {
posts: posts.slice(0, 5),
},
}
}
// pages/posts/[id].js
import { useRouter } from 'next/router'
export default function Post({ post }) {
const router = useRouter()
if (router.isFallback) {
return <div>Loading...</div>
}
return (
<div>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
)
}
export async function getStaticPaths() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts')
const posts = await res.json()
const paths = posts.slice(0, 5).map((post) => ({
params: { id: post.id.toString() },
}))
return { paths, fallback: true }
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`)
const post = await res.json()
return { props: { post } }
}
この例では、外部APIからブログ記事のデータを取得し、トップページに表示しています。各記事にはリンクが設定されており、クリックすると詳細ページに遷移します。詳細ページでは、記事の全文を表示しています。
以上が、Next.jsを使用した実践的なブログアプリケーションの基本的な実装例です。この基礎をもとに、さら