【Next.js】Map関数を使ってDaisyUIのCardをループで表示する方法

# Daisy UIのCardをループで表示させたい！
DaisyUIの公式サイトにも、ネット上にもなかなか情報が無かったので、備忘録として記録しておきます。

https://daisyui.com/components/card/

# サンプルイメージ
ちょっと見えにくいですが、下記のようにデータベースから取得してきたイベント情報をダッシュボードに一覧表示させるサンプルです。

![DaisyUIサンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/f3bcaeeb-d206-d21d-8552-d31fdd8f30d6.png)




# ディレクトリ構造
今回紹介するのは「★★」のついたコードです。

```
└── プロジェクト/
    ├── モジュール群
    └── app/
        ├── auth/
        │   └── eventRegister 
        ├── login/
        │   ├── dashboard/
        │   │   └── page.tsx　←←★これ★
        │   └── page.tsx 
        ├── logout/
        │   └── page.tsx
        ├── register/
        │   └── page.tsx
        ├── components/
        │   ├── card/
        │   │   └── page.tsx　←←★これ★
        │   ├── footer/
        │   │   └── page.tsx
        │   └── navbar/
        │       └── page.tsx
        ├── lib /
        │   ├── db.ts
        │   └── prisma.ts
        └── pages/
            └── api/
                ├── eventRegister.ts
                ├── login.ts
                ├── register.ts
                └── upload.ts

```

# サンプルコード
「app/login/dashuboard/page.tsx」ファイルでは下記の仕様になっています。
①useEffectフックを使ってデータベースからユーザーIDをキーにして全イベント情報を非同期で取得する。※ここではクエリの引数を1にしています。(登録されているユーザーIDが1であるため)

```app/login/dashuboard/page.tsx
    useEffect(()=>{
        // 非同期データ取得関数
        const fetchEvents = async () => {
            //非同期なのでawait修飾子を必ずつける
            events =await SelectAllEvents(Number(1)); // ユーザーIDを使ってイベントを取得
        
        //以降の処理は省略
    }
```

<b>注意：use clientファイルでは関数に「async」や「await」を使用することは使用されません。<br>なので、非同期処理を使用する場合はuseEffectなどのフックを使って処理を行いましょう</b>

②非同期で取得した全イベントを配列に格納します。
```app/login/dashuboard/page.tsx
//★【重要】取得したイベント「events[0]」を状態にセットする
setGetEvents(events[0]);
```

③イベント情報が更新されるたびに情報をコンソールに出力して確認します
```app/login/dashuboard/page.tsx
    // ここでは、getEventsの0番目のデータをconsole.logで出力する
    useEffect(() => {
        if (getEvents.length > 0) {
            console.log("GetEventsのデータ配列の長さは：" + getEvents[0].length); // 配列の0番目を出力
            console.log("GetEventsのデータは："+getEvents[0]); // 配列の0番目を出力
            console.log("GetEventsの最初のデータは："+getEvents[0][0]); // 配列の0番目を出力
            console.log("取得したsetGetEvents配列の長さは、" + getEvents[0].length);
            
        }
    }, [getEvents]); // getEventsが更新されるたびに実行 
```

ここまでの全コードは下記に示します。↓

```app/login/dashuboard/page.tsx
'use client'//←忘れずに記載すること

import { useForm } from "react-hook-form";
import { useRouter } from "next/navigation";
import Navbar from "@/app/components/navbar/page";
import Footer from "@/app/components/footer/page";
import Card from "@/app/components/card/page";
import SelectAllEvents from "@/app/pages/api/selectAllEvents";
import { useState,useEffect } from "react";
import { QueryResult } from "mysql2";


export default function dashboard(){
    const [userId,setUserId] = useState(0);//sessionStorage.getItem("id")
    const [getEvents, setGetEvents] = useState<any[]>([]); // getEventsを状態として定義
    
    const router = useRouter();   
    //const userId = sessionStorage.getItem("id");
    const userEmail = sessionStorage.getItem("email");
    const userPassword = sessionStorage.getItem("password");
    console.log("セッションのユーザIDは、"+userId);

    let changeUserId = Number(sessionStorage.getItem("id"));
    console.log("変更後のセッションユーザーIDは、" + changeUserId);
    //setUserId(Number(sessionStorage.getItem("id")));
    //console.log("セッションのユーザIDは、"+setUserId);

    if(userId == null){
        return null;
    }

    //全イベントを格納する配列
    let events:any[];
    
    useEffect(()=>{
        // 非同期データ取得関数
        const fetchEvents = async () => {
            //非同期なのでawait修飾子を必ずつける
            events =await SelectAllEvents(Number(1)); // ユーザーIDを使ってイベントを取得 userId ※ここでは暫定的に1を付け手検証
            
            //取得した配列の個数を出力する
            console.log("取得した配列の長さは、" + events[0].length);
                        
            console.log("コンソール画面に出力するデータは：" + JSON.stringify(events)); // コンソールに出力
            console.log("コンソール画面に出力する最初のデータは：" + events[0][0]); // コンソールに出力
            const jsonEvents:any = JSON.stringify(events[0][0]);
            console.log("コンソール画面に出力するJSONデータは：" + jsonEvents); // コンソールに出力
            
            //[検証]最初のレコードからイベントタイトルを変数に格納する
            const event = events[0][0];
            //[検証]最初のレコードからイベントタイトルをコンソールに出力
            console.log(event.eventtitle);

            //★【重要】取得したイベント「events[0]」を状態にセットする
            setGetEvents(events[0]);
            
            console.log("eventsの値は、" + events);                     
        };
        
        fetchEvents(); // イベント取得を実行                    
    },[userId])

    // ここでは、getEventsの0番目のデータをconsole.logで出力する
    useEffect(() => {
        if (getEvents.length > 0) {
            console.log("GetEventsのデータ配列の長さは：" + getEvents[0].length); // 配列の0番目を出力
            console.log("GetEventsのデータは："+getEvents[0]); // 配列の0番目を出力
            console.log("GetEventsの最初のデータは："+getEvents[0][0]); // 配列の0番目を出力
            console.log("取得したsetGetEvents配列の長さは、" + getEvents[0].length);
            
        }
    }, [getEvents]); // getEventsが更新されるたびに実行 
            
    console.log("一番外のgetEventsは、" + JSON.stringify(getEvents[0]));
    
    return(
        <div>
            <Navbar></Navbar>
            <div className="cardArea">                                               
                {getEvents.length > 0 && getEvents.map((event)=>( 
                    <Card event={event} key={event.eventid}></Card>
                ))}                                                                                                            
            </div>
            {/* getEventsの0番目を表示する部分 */}
            ログイン後のページ
            <div>ユーザーID：{userId}</div>
            <div>ユーザーEmail：{userEmail}</div>
            <div>ユーザーパスワード：{userPassword}</div>
            <Footer></Footer>
        </div>
    );
}

```

Cardのコンポーネントは下記のとおりです。
eventの各情報を表示する関数です。
|項目        |変数                   |
|----       |----                   |
|ユーザーID  |userid                 |
|イベントID|eventid|
|イベントタイトル|eventtitle|
|イベント内容|eventdetail|
|イベントの画像パス|eventthumbnailpath|

```app/components/card/page.tsx
'use client'

import SelectAllEvents from "@/app/pages/api/selectAllEvents";
import { QueryResult } from "mysql2";

type Event = {
    id:number;
    title:string;
    description:string;
    imageUrl:string
}

//const {userid,eventid,eventtitle,eventdetail,eventthumbnailpath} = event;

export default function Card({event}) {
    const {userid,eventid,eventtitle,eventdetail,eventthumbnailpath} = event;
                                                         
    return (
        <div>                                   
            <div className="card bg-base-100 w-96 shadow-xl">
                <div>{userid}</div>
                <div>{eventid}</div>                               
                <div className="card bg-base-100 w-96 shadow-xl">
                
                    <figure>
                        <img src={eventthumbnailpath} alt="No Image"/>
                    </figure>
                    <div className="card-body">
                        <h2 className="card-title">{eventtitle}</h2>
                        <p>{eventdetail}</p>
                        <div className="card-action justify-end">
                            <button className="btn btn-primary">参加</button>
                        </div>
                    </div>
                </div>                
            </div>
        </div> 
    );
}
```

以上です。