はじめに
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編)
https://qiita.com/naoyuki2/items/2d8ad09f767f818e8860
【03】Next.js14でTodoアプリ作成(INSERT編)
https://qiita.com/naoyuki2/items/27d550ab3766a1869aaf
【04】Next.js14でTodoアプリ作成(DELETE編)
今回のゴール
データの更新ができるようになる。とはいっても、完了、未完了の値(isDone)のみ更新できるようにする。
1.APIの作成(PATCHメソッド)
PATCHメソッドの記述
src/app/api/todo/[id]/route.tsにPATCHメソッドを記述していく。DELETEメソッドがすでにあるのでその下に書く。
export async function PATCH(
request: Request,
{ params }: { params: { id: string } },
) {
// todoテーブルのレコードを更新
const body = await request.json()
const id = Number(params.id)
try {
const todo: todo = await prisma.todo.update({
where: {
id: id,
},
data: {
isDone: body.isDone,
},
})
return NextResponse.json(todo)
} catch (error) {
return NextResponse.json(error)
}
}
コードの解説
前回の記事で解説したところは省略する。
const todo: todo = await prisma.todo.update({
where: {
id: id,
},
data: {
isDone: body.isDone,
},
})
return NextResponse.json(todo)
今回はprismaのupdate関数を使う。
whereには前回と同様にリクエストパラメータから取得したidを使用する。
今回はisDoneのみ更新するためdataに変更するカラム名(isDone)と値を記述する。
2.フロントエンドの実装
前回の記事からpatchTodo関数とチェックボックスを追加した。
コードの全体
'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('')
}
const deleteTodo = async (id: number) => {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/todo/${id}`,
{
method: 'DELETE',
},
)
const data = await res.json()
setTodos(todos.filter((todo) => todo.id !== data.id))
}
+ const patchTodo = async (todo: todo) => {
+ const res = await fetch(
+ `${process.env.NEXT_PUBLIC_API_URL}/todo/${todo.id}`,
+ {
+ method: 'PATCH',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ isDone: !todo.isDone,
+ }),
+ },
+ )
+ const data = await res.json()
+ setTodos(
+ todos.map((todo) => {
+ if (todo.id === data.id) {
+ return data
+ }
+ return todo
+ }),
+ )
+ }
return (
<>
<input
placeholder="タイトル入力"
value={inputVal}
onChange={(e) => setInputVal(e.target.value)}
/>
<button onClick={() => postTodo()}>追加</button>
{todos.map((todo) => (
<div key={todo.id}>
+ <input
+ type="checkbox"
+ checked={todo.isDone}
+ onChange={() => patchTodo(todo)}
+ />
<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>
<button
onClick={() => deleteTodo(todo.id)}
className="bg-rose-400 px-2 py-1 rounded"
>
削除
</button>
</div>
))}
</>
)
}
コードの解説
const patchTodo = async (todo: todo) => {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/todo/${todo.id}`,
{
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
isDone: !todo.isDone,
}),
},
)
bodyにはisDoneを反転した(!をつけると反転)値を渡す。falseの状態でチェックボックスをクリックしたらtrueに、逆にtrueの状態でクリックしたらfalseに。
const data = await res.json()
setTodos(
todos.map((todo) => {
if (todo.id === data.id) {
return data
}
return todo
}),
)
}
現在保存されているtodoをmap関数で一つずつ取り出す。
取り出したtodoのidと、変更したdataのidが一致していれば、受け取ったdataの方を返す。
一致していない場合は今まで通りのtodoを返す。
3.更新してみよう
チェックボックスをクリックして変更されれば成功。
おわりに
これでCRUD処理は全て実装完了!でも他にも色々つけ足してみよう。
参考にさせていただいた記事

