・Next.js: 13.5.1
・Swr: 2.2.2
・Axios: 1.5.0
・Zod: 3.21.4
// app/counter/page.tsx.
'use client'
import { useEffect, useState } from 'react'
export default function Counter() {
// useStateを利用してクリックした回数を保持
const [count, setCount] = useState(0)
// countの値が変わるたびに実行
useEffect(() => {
console.log('count', count)
}, [count])
// ボタンを押下するたびに実行
const handleClick = () => {
setCount(count + 1)
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={handleClick}>Click</button>
</div>
)
}
https://nextjs.org/docs/app/building-your-application/routing/route-handlers
$ npm install swr axios
app
├── routeHandlers
│ └── page.tsx ← クライアントで実行
└── api
└── routeHandlers
└── route.ts ← サーバーで実行
'use client'
import axios, { AxiosResponse } from 'axios'
import useSWR from 'swr'
import { useState } from 'react'
type TestResponse = {
userId: string
id: string
title: string
body: string
}
type TestRequest = {
url: string
postId: string
}
const fetcher = async (request: TestRequest) =>
await axios
.post(request.url, { postId: request.postId })
.then((res: AxiosResponse<TestResponse>) => res.data)
export default function RouteHandlers() {
const [postId, setPostId] = useState('1')
const { data, error, isLoading } = useSWR<TestResponse, Error>(
['/api/routeHandlers', postId],
([url, postId]: [url: string, postId: string]) => fetcher({ url, postId }),
)
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
const targetElement = e.currentTarget?.postId as HTMLInputElement
if (targetElement) {
setPostId(targetElement.value)
}
}
if (error) {
return <div>Failed to load</div>
}
if (isLoading) {
return <div>Loading...</div>
}
return (
<div>
<div>
<form onSubmit={handleSubmit}>
<input name='postId' type='number' required placeholder='enter postId' />
<button>search</button>
</form>
</div>
<div>
{data && Object.keys(data).length !== 0 ? (
<div>
<div key={data.id}>
<h3>{data.title}</h3>
<p title={data.body}>{data.body}</p>
</div>
</div>
) : (
<h2>Not found</h2>
)}
</div>
</div>
)
}
import 'server-only'
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
const userSchema = z.object({
postId: z.string(),
})
type TestResponse = {
userId: string
id: string
title: string
body: string
}
export const POST = async (request: NextRequest) => {
try {
const result = userSchema.safeParse(await request.json())
if (!result.success) {
return NextResponse.json({}, { status: 400 })
}
const postId = result.data.postId.trim()
const post = (await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`).then((res) =>
res.json(),
)) as TestResponse
if (!post || Object.keys(post).length === 0) {
return NextResponse.json({}, { status: 500 })
}
return NextResponse.json(post, { status: 200 })
} catch (error) {
return NextResponse.json({}, { status: 500 })
}
}
以上で全ての手順は完了になります