はじめに
Next.jsの知識を深めるために、Todoアプリを作ることにしました。そのメモを残しておきます。今回はデータ挿入についてのメモを残します。何か間違っていることなどございましたらコメントいただけますと、とても喜びます。
今までの記事
環境構築編
https://qiita.com/naoyuki2/items/e974c630c6cbd3c55254
【01】Next.js14でTodoアプリ作成(CREATE編)
https://qiita.com/naoyuki2/items/7474d448de7769905d82
【02】Next.js14でTodoアプリ作成(SELECT編)
今回のゴール
データ挿入ができる
1.APIの作成(POSTメソッド)
POSTメソッドの記述
src/app/api/todo/route.ts
にPOST
メソッドを記述していく。GET
メソッドがすでにあるのでその下に書く。
export async function POST(request: Request) {
// todoテーブルに新規レコードを追加
const body = await request.json()
try {
const todo: todo = await prisma.todo.create({
data: {
title: body.title,
},
})
return NextResponse.json(todo)
} catch (error) {
return NextResponse.json(error)
}
}
コード解説
export async function POST(request: Request) {
この関数はHTTPリクエストを引数として受け取る。
Request
という型がNext.jsで用意されているらしく、import
せずとも使えるらしい。反対にResponse
という型もある。
const body = await request.json():
この行は、受け取ったレスポンスからJSONデータを非同期に解析する。この中にtitle
が入っている。
const todo: todo = await prisma.todo.create({
data: {
title: body.title,
},
})
Prisma
のcreate
関数を使用して新しいtodo
レコードをデータベースに挿入する。SQLでいうINSERT INTO "todo" (title) values (body.title)
みたいなこと。
return NextResponse.json(todo)
新しく作成された"todo"レコードをJSON形式で返す。
2.フロントエンドの実装
全部載せてるんで見ずらい。ごめんなさい。+
がついている緑の行を前回から新たに追加した。
コードの全体
'use client'
import { useEffect, useState } from 'react'
import { todo } from '@prisma/client'
export default function Home() {
const [todos, setTodos] = useState<todo[]>([])
+ const [inputVal, setInputVal] = useState<string>('')
useEffect(() => {
const getTodo = async () => {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/todo`)
const data = await res.json()
setTodos(data)
}
getTodo()
}, [])
+ const postTodo = async () => {
+ if (!inputVal) return alert('タイトルを入力してください')
+ const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/todo`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ title: inputVal,
+ }),
+ })
+ const data = await res.json()
+ setTodos([...todos, data])
+ setInputVal('')
+ }
return (
<>
+ <input
+ placeholder="タイトル入力"
+ value={inputVal}
+ onChange={(e) => setInputVal(e.target.value)}
+ />
+ <button onClick={() => postTodo()}>追加</button>
{todos.map((todo) => (
<div key={todo.id}>
<p>{todo.id}</p>
<p>{todo.title}</p>
<p>{todo.content}</p>
<p>{todo.isDone}</p>
<p>{new Date(todo.createdAt).toLocaleString()}</p>
<p>{new Date(todo.updatedAt).toLocaleString()}</p>
</div>
))}
</>
)
}
コードの解説
const [inputVal, setInputVal] = useState<string>('')
タイトルを入力するinput
要素のvalue
属性を管理するためにuseState
を使用する。
const postTodo = async () => {
if (!inputVal) return alert('タイトルを入力してください')...
postTodo
関数を実行時にinputVal
の中身が空だった場合はアラートを出し、return
があるのでここで関数が終了する。
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/todo`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: inputVal,
}),
})
前々回の記事で.env
ファイルにAPIルートを書いているため、今回も流用する。
今回はPOST
メソッドなのでmethod
タイプを記述する。
JSON
形式でやり取りするため、headers
にこのような記述をする。
body
にはAPI
に渡すものを記述する。今回はtitle
のみでいいのでtitle
情報を保持しているinputVal
を渡す。
const data = await res.json()
setTodos([...todos, data])
setInputVal('')
返ってきたレスポンスをJSON
形式でdata
に代入する。
useState
のsetTodos
でtodos
にデータを入れる。
...todos
はスプレッド構文といって配列の中身を展開することができる。todos
を展開して、data
を新しく追加している。
setInputVal('')
でinput
要素を空にして次のタイトルを入力しやすいようにしている。
<input
placeholder="タイトル入力"
value={inputVal}
onChange={(e) => setInputVal(e.target.value)}
/>
value
にはuseState
のinputVal
を設定する。
そして、onChange
イベントを設定することでinput
要素の中身が変更されるたびにinputVal
の値を更新している。
<button onClick={() => postTodo()}>追加</button>
onClick
イベントにより、先ほど作ったpostTodo
関数を呼び出している。
3.挿入できるか試す!
これでおそらくデータの挿入ができるはず!!
空だったら下のようにアラートが出る。
テスト
と入力して、追加
をクリックすると下にテスト
というデータが追加されるはず。
おわりに
POST
はまだ簡単な気がする。UPDATE
やDELETE
は条件が増えて大変そう。