0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Next.js】PostgreSQLで取得したデータをCardで表示させる方法2

Posted at

サンプル

このような画面をサーバからデータを取得・表示します。
画面.png

フロント側

コードを見て、いくつか注意すべきポイントがあります。
特に、商品リストを表示する部分で 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つの注文には複数のアイテムが関連付けられる
}

以上です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?