こんにちは。 アドベントカレンダー24日目です。 今年はフロントエンドまわりであれこれ開発することが多かったので、振り返りを兼ねてこれからフロントエンド開発を始める方向けに入門編としてお送りしています。 最終日の25日には何かアプリケーションができていることが目標です。
↓最初から読み始めたい方はこちらか↓
おさらい
- Visual Studio Codeを使ったReactの開発環境の構築(第1回)
- CSSフレームワークの1つであるtailwindcssを使ったUI開発(第2回)
- コンポーネント化(第3回)
- フォーマッター(第4回)
- Linter(第5回)
- バージョン管理(第6回)
- 状態管理とReact hook form(第7回、第8回、第11回))
- Visual Studio Codeの設定(第9回、第10回、第16回、第17回)
- Reactルーティング(第12回)
- Playwright(第13回、第14回)
- GitHub CodespacesでAmplify
- 環境立ち上げとCLIツールの有効化(第15回)
- Amplifyで初期プロジェクト作成(第18回)
- Amplifyで認証機能作成(第19回)
- AmplifyでAPI機能作成(第20回)
- Amplifyで書籍登録機能(第21回)
- Amplifyで書籍取得機能(第22回)
- Amplifyで書籍更新機能(第23回)
今回のはなし
第18回からAmplifyシリーズでお送りしています。「書籍管理アプリ」を作りながらAPI機能の基本的な使い方を学んでいます。前回は、書籍更新の処理を作りました。今回は登録した書籍情報を削除できるように削除機能を追加していきましょう。
pages
├── app.css
├── _app.tsx
├── book
│ ├── createBookData.ts
│ ├── [id]
│ │ ├── edit.tsx
│ │ ├── fetchbook.ts
+ │ │ └── updateBookData.ts
│ └── resister.tsx
├── deleteBookData.ts
├── fetchBooks.ts
└── index.tsx
まずは、削除するための関数を作ります。これまでと同じように部分的に異なるくらいで、ほとんと書き方はこれまでと同じようなものなので、細かい説明は省略します。
import { Book, DeleteBookMutation } from "@/src/API"; import { deleteBook } from "@/src/graphql/mutations"; import { GraphQLResult, generateClient } from "aws-amplify/api"; export default async function deleteBookData(id: string) { const client = generateClient(); const response = await client.graphql({ query: deleteBook, variables: { input: { id } }, }) as GraphQLResult<DeleteBookMutation>; if (response.errors) { throw new Error(response.errors[0].message); } if (!response.data?.deleteBook) { throw new Error("Book not created"); } const book: Book = response.data?.deleteBook; return book; }
作成した削除関数はuseBook内で使用します。このように削除処理を記述してください。削除処理に成功した場合は、カスタムフック内で保持している配列から当該のデータを削除します。そすることで、画面上からの一覧からもリアルタイムにデータを消すことができます。
+ import deleteBookData from "@/pages/deleteBookData"; import fetchBooks from "@/pages/fetchBooks"; import { Book } from "@/src/API"; import { useEffect, useState } from "react"; export default function useBook() { const [books, setBooks] = useState<Book[]>([]); const [loading, setLoading] = useState(false); const [error, setError] = useState<Error | null>(null); useEffect(() => { fetchBooks() .then((books) => { setBooks(books); }) .catch((error) => { setError(error); }).finally(() => { setLoading(false); }); }, []); + const deleteBook = async (id: string) => deleteBookData(id) + .then((book) => { + setBooks((books) => books.filter((book) => book.id !== id)); + }).catch((error) => { + throw error; + }); return { books, loading, error, deleteBook }; }
カスタムフックの修正ができたらpages/index.tsxから先ほど作成したdelete関数を呼び出します。
...
export default function Home() {
const {
books,
loading,
error,
+ deleteBook
} = useBook();
...
+ const handleDelete = async (id: string) => {
+ const confirm = window.confirm("本当に削除しますか?");
+ if (!confirm) {
+ return;
+ }
++ deleteBook(id)
+ .then(() => {
+ alert("削除しました");
+ }).catch(() => {
+ alert("削除に失敗しました");
+ });
+ }
return (
<div className="space-y-5">
<h3 className="text-3xl font-bold dark:text-white">書籍一覧</h3>
<div>
<Link href="/book/resister" className="text-blue-500 hover:text-blue-700">
書籍を登録する
</Link>
</div>
<div>
<table className="border-collapse border border-slate-400 table-auto">
...
<tbody>
{books.map((book) => (
<tr>
<td className="border border-slate-300 p-2">{book.id}</td>
<td className="border border-slate-300 p-2">{book.isbn || "(なし)"}</td>
<td className="border border-slate-300 p-2">{book.name}</td>
<td className="border border-slate-300 p-2">
{book.auther?.filter((item): item is NonNullable<typeof item> => !!item).join(", ")}
</td>
<td className="border border-slate-300 p-2">{book.publisher}</td>
<td className="border border-slate-300 p-2 space-x-2">
<Link
href={`/book/${encodeURIComponent(book.id)}/edit`}
className="text-blue-500 hover:text-blue-700"
>
編集
</Link>
+ <button
+ type="button"
+ className="text-red-500 hover:text-red-700 whitespace-nowrap"
+ onClick={() => handleDelete(book.id)}
+ >
+ 削除
+ </button>
+ </td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
これで削除処理を追加することができました。
おわりに
これで一通りの機能は簡易的ですが、実装することができました。これで書籍管理アプリは完成です。思っていたよりも簡単に処理を作れることが実感できたのではないでしょうか。 最後に書籍情報を追加してファイルを
