📝
【開発ログ】単語カードをAPI経由で取得して一覧表示まで実装
単語カード一覧の取得まで進みました。まだ自分が思い描いている完成形には遠いですが、
大きな流れはできてきたので、これからは細かい UI/UX の改善やデータ加工、エラー処理に注力していきます。
前回
- タグ機能(検索・フィルタリング対応も検討)
- Word 登録時に既存タグを選択 or 新規タグを作成できるよう修正
- タグ一覧をフロントから取得して UI で選択可能に
今回
- 単語カードを API から取得
① 単語カードを API から取得
まずはログインユーザが登録した単語カードを API 経由で取得できるようにしました。
Prisma で Word を検索し、必要なフィールドだけ DTO に整形して返すように実装。
export async function GET() {
/* const user = "セッションクッキーを使ってuser情報取得”**/
const wordList = await prisma.word.findMany({
where: { userId: user.id },
include: { image: true, tags: true },
orderBy: { createdAt: "asc" },
});
//必要なデータの整形
const dto = wordList.map((w) => ({
id: w.id,
ja: w.jaSurface,
ko: w.koSurface,
imgUrl: w.image?.imageUrl ?? "https://via.placeholder.com/300x200",
tags: w.tags.map((t) => t.name),
status: w.status,
}));
return NextResponse.json(dto);
}
② フロントでの取得と表示
フロントエンド側では useEffect を使って /api/learn からカード一覧を取得。
取得した配列を map で描画するだけで、ユーザーの単語カード一覧を表示できるようになりました。
"use client";
import { useEffect, useState } from "react";
import { LearningCardData } from "@/types/lesson";
export default function LearningCardList() {
const [cards, setCards] = useState<LearningCardData[]>([]);
useEffect(() => {
const fetchCards = async () => {
const res = await fetch("/api/learn", { cache: "no-store" });
const data = await res.json();
setCards(data);
};
fetchCards();
}, []);
return (
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
{cards.map((card) => (
<article key={card.id} className="rounded-2xl border p-4 shadow-sm">
<div className="relative aspect-[4/3] mb-3 overflow-hidden rounded-xl bg-gray-100">
<img src={card.imgUrl} alt={`${card.ja} / ${card.ko}`} className="object-cover" />
</div>
<h2 className="text-lg font-semibold">
{card.ja} <span className="text-gray-500">/ {card.ko}</span>
</h2>
<div className="mt-2 flex flex-wrap gap-2">
{card.tags.map((t) => (
<span key={t} className="text-xs rounded-full border px-2 py-1">
{t}
</span>
))}
</div>
<div className="mt-3">
<span
className={`text-xs px-2 py-1 rounded ${
card.status === "published"
? "bg-green-100 text-green-700"
: "bg-yellow-100 text-yellow-700"
}`}
>
{card.status}
</span>
</div>
</article>
))}
</div>
);
}
実際の表示

悩んだこと / 学んだこと
-
useEffect内で API を呼ぶと、開発モードでは複数回実行されてしまう
→ 原因は React StrictMode。開発時のみ無効化。 -
取得データをそのまま扱うと複雑になる
→ DTO に加工し、UI 側では必要なフィールド(id, ja, ko, imgUrl, tags, status)のみ利用することでコードをシンプルに扱える
次回やること
- タグ別検索・フィルタリングの実装
- UI デザインの再調整(ボタンの色・一覧性改善)
- 新しい単語を保存しようとするとセッションエラー発生 → ログイン中でもセッション満了になるケースを調査・解決
Discussion