サンプル
フロント側
コードを見て、いくつか注意すべきポイントがあります。
特に、商品リストを表示する部分で map
メソッドの返り値が Card
コンポーネントに渡す必要があります。
1. 商品リストの表示部分の修正
inventoryProducts.map
の中で、Card
コンポーネントを返却します。
map
は要素を返す必要があるので、返り値に return を追加する必要があります。
結論:
map
メソッド内で Card
コンポーネントを返すようにしました (return を追加)。
inventoryProducts
が null の場合を考慮して、条件分岐を追加しました。
もし inventoryProducts
が空でない場合、商品を表示し、空の場合には「商品が見つかりませんでした」と表示します。
全体のコードは下記となります。
app/product/productList/page.tsx
'use client'//付けること
import ProductNavBar from "@/app/components/productHeaders/navbar/page"
import Card from "@/app/components/card/page"
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
export default function ListOfProducts(){
const router = useRouter();
const [inventoryProducts,setInventoryProducts] = useState<any>(null);
useEffect(()=>{
const fetchEvent = async()=>{
try{
const productslist = await fetch('/api/products/readAllProducts',{
method:'GET'
});
const data = await productslist.json();
console.log("productリストは、",data);
setInventoryProducts(data);
//console.log("商品の在庫は、",data);
if(Array.isArray(data) && data.length > 0){
//商品リストがあれば登録する
setInventoryProducts(data);
console.log("setInventoryProductsのデータは、",setInventoryProducts(data));
}else{
setInventoryProducts([]);
}
}catch(error){
alert('商品リストの取得に失敗しました。');
}
};
fetchEvent();
},[]);
console.log("在庫のJSONデータの全部のinventoryProductsは、",inventoryProducts);
return (
<div className="shadow-md border border-gray-500 rounded-md">
<ProductNavBar></ProductNavBar>
<main className="flex items-center justify-center w-full ml-4 mt-4 mb-4 mr-4">
<div className="cardArea grid grid-cols-3 gap-4">
{inventoryProducts && inventoryProducts.length > 0 ? (
inventoryProducts.map((product)=>{
return <Card product={product} key={product.productId}></Card>
})
):(
<p>商品が見つかりませんでした。</p>
)}
</div>
</main>
</div>
)
}
Cardコンポーネントの作成
app/components/card/page.tsx
'use client'//Next.jsはデフォルトはサーバ側の設定である
import { useRouter } from "next/navigation";
export default function Card({product}){
//ルーティング設定
const router = useRouter();
//詳細を見るボタンクリックしたときの処理
const clickProductDetail = ()=>{
router.push('');
}
const {productId,productName,description,productImagepath,price,quantity} = product;
return (
<div>
<div>
<div>
<input type="hidden" name="productId" value={productId}/>
</div>
</div>
<div>
<figure>
<img src={productImagepath} alt="No Imagae"/>
</figure>
<div className="card-body">
<h2 className="card-title">{productName}</h2>
<p>{description}</p>
<p>{price}円(yen)</p>
<p>{quantity}</p>
<div>
<button
type="button"
className="bg-blue-500 shadow-md text-white font-bold px-4 py-4 rounded-md"
onClick={clickProductDetail}
>
詳細を見る
</button>
</div>
</div>
</div>
</div>
)
}
サーバ側
フロント画面へは、JSON形式で返却するようにしました。
app/api/products/readAllProducts/route.ts
import { NextResponse } from "next/server";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export async function GET(){
try{
//商品をすべて取得する
const allProductsList = await prisma.product.findMany({
/*
include:{
items:true // Itemテーブルのデータを含めて取得
}
*/
});
console.log("すべての商品:",allProductsList);
//HTTP Status:500(データベース接続エラー)
if(!allProductsList){
return NextResponse.json({message:'商品が1つも登録されていません。',status:500});
}
return NextResponse.json(allProductsList);
}catch(error){
//HTTP Status503(サーバ停止またはメンテナンス中)
return NextResponse.json({message:'データベース停止またはメンテナンス中です。',status:503});
}
}
スキーマ構造
スキーマも載せておきます。
schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User{
userId Int @id @default(autoincrement())
userName String
email String @unique
password String
createdAt DateTime @default(now())
orders Order[] // 1人のユーザーは複数の注文を持つ
}
model AdminUser{
adminUserId Int @id @default(autoincrement())
adminUserName String
adminEmail String @unique
adminPassword String
createdAt DateTime @default(now())
products Product[] // 1人の管理者は複数の商品を管理できる
}
model Product{
productId Int @id @default(autoincrement())
productName String
quantity Int @default(0) //売価
price Int @default(0) //仕入れ数量
description String
productImagepath String
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
items Item[] // 1つの製品は複数のアイテムに関連付けられる
adminUserId Int // 管理者が商品を管理
adminUser AdminUser @relation(fields: [adminUserId], references: [adminUserId]) // 管理者とのリレーション
}
model Item{
itemId Int @id @default(autoincrement())
quantity Int
price Int
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
productId Int // Product と 多対1 のリレーション
product Product @relation(fields: [productId], references: [productId])
orderId Int // Order と 1対多 のリレーション
order Order @relation(fields: [orderId], references: [orderId])
}
model Order{
orderId Int @id @default(autoincrement())
total Int
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
userId Int // User と 1対多 のリレーション
user User @relation(fields: [userId], references: [userId])
items Item[] // 1つの注文には複数のアイテムが関連付けられる
}
以上です。