【Next.js】データを更新して一覧表示するまでの流れを解説

# サンプルのイメージ
個人開発で下記の①編集画面からイベント情報を入力して、②イベント一覧に戻って一覧を表示するサンプルを解説してみます
(作りかけなので、温かい目で見てやってください。備忘録も兼ねてます)

<b>①編集画面</b>
![編集画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/61985112-1707-1b83-ec1c-35bcb44fb7fb.png)

<b>②一覧画面</b>
![編集一覧画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/448730a4-2103-5337-ec17-6cae9156b8d4.png)

# まずは①編集画面のコードから解説

![編集画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/bdf07738-1e2c-4ac1-151d-48197ea1b573.png)

今回の個人開発で必要なパーツは下記です。
①イベント名
②イベント内容
③イベントサムネイル

なので、イベント一覧画面から編集対象のイベントを選びこの画面に宣した時にデータベースからレコードを取得します。
```app/auth/eventEdit/page.tsx
    useEffect(()=>{
        const fetchEvent = async ()=>{
            try{
                
                const event = await SelectEvent(Number(userId),Number(eventId));
                console.log("サーバから取得してきた編集対象イベントは、" + event[0]);
                console.log("サーバから取得してきた編集対象イベントは、" + event[0].userid);
                settargetEvent(event[0]);
                                                                                                                                            
            }catch(error){
                console.error("イベントの取得中にエラーが発生しました：", error);
            }
        };
        fetchEvent();                
    },[userId,eventId]);//[userId,eventId]
```

編集情報を入力したら、再度データベースに登録します。
このコードでは、
１．FormData形式で取得したイベント情報を引数にデータベースに登録する。
２．データベース登録後、完了フラグ(TrueまたはFalse)を取得し、True値ならばRouterを使って一覧画面に遷移する。

↑このようなロジックになっています。
```app/auth/eventEdit/page.tsx
    //編集データを更新(登録)する
    const handleSubmit = useCallback(async (e:React.FormEvent<HTMLFormElement>)=>{
        console.log("更新ボタンを押下しました");
        e.preventDefault();
        const formData = new FormData(e.target as HTMLFormElement);
        console.log("編集後のイベント内容は、" + formData);
        const success = await editTargetEvent(formData);
        if(success){
            router.push("/auth/login/dashboard");
        }else{
            setError("イベントの更新に失敗しました。");
        }
        setLoading(false);
    },[router]);
```

全体のコードはこちら↓


```app/auth/eventEdit/page.tsx
'use client'

import { useRouter, useSearchParams } from "next/navigation"
import { useCallback, useEffect,useState } from "react";
import SelectEvent from "@/app/pages/api/selectEvent";
import editTargetEvent from "@/app/pages/api/editEvent";
//import { GETQueryParams } from "@/app/pages/api/urlQueryParameters";

export default function EventEdit(){
    //ルーティングの設定
    const router = useRouter();
    const [loading,setLoading] = useState(false);
    const [error,setError] = useState<string | null>(null);

    //クライアントコンポーネントフックであるuseSearchParamsを使用する
    const searchParams = useSearchParams();
    //const [targetUserId,settargetUserId] = useState(0);

    //URL Query Paramsからパラメータを取得する
    const userId = searchParams.get('userId');
    const eventId = searchParams.get('eventId');

    console.log("GETパラメータから受け取ったユーザーIDは、" + userId);
    console.log("GETパラメータから受け取ったイベントIDは、" + eventId);

    //ダッシュボードに戻るボタン押下時の処理
    const backToMyDashboard = ()=>{
        router.push("/auth/login/dashboard");
    }
    //状態でイベント情報を管理する
    const [targetEvent,settargetEvent] = useState<any[]>([]);//useState<any>(null);
    
    //let event:any;
    useEffect(()=>{
        const fetchEvent = async ()=>{
            try{
                console.log("内部のユーザーIDは、" +userId);
                const event = await SelectEvent(Number(userId),Number(eventId));
                console.log("サーバから取得してきた編集対象イベントは、" + event[0]);
                console.log("サーバから取得してきた編集対象イベントは、" + event[0].userid);
                settargetEvent(event[0]);

                console.log("useeffectの編集対象のイベントは、" + JSON.stringify(event[0]));                                                                                                                            
            }catch(error){
                console.error("イベントの取得中にエラーが発生しました：", error);
            }
        };
        fetchEvent();                
    },[userId,eventId]);//[userId,eventId]

    //let jsonEvent = JSON.stringify(targetEvent);
    //console.log("外の編集対象のイベントは、" + jsonEvent);
    console.log("useEffect外の編集対象のユーザIDは、" + targetEvent.userid);
    console.log("useEffect外の編集対象のイベントタイトルは、" + targetEvent.eventtitle);            

    console.log("useEffect外の編集対象のイベントタイトル(targetEventtitle)は、" + targetEvent.eventtitle);

    //編集データを更新(登録)する
    const handleSubmit = useCallback(async (e:React.FormEvent<HTMLFormElement>)=>{
        console.log("更新ボタンを押下しました");
        e.preventDefault();
        const formData = new FormData(e.target as HTMLFormElement);
        console.log("編集後のイベント内容は、" + formData);
        const success = await editTargetEvent(formData);
        if(success){
            router.push("/auth/login/dashboard");
        }else{
            setError("イベントの更新に失敗しました。");
        }
        setLoading(false);
    },[router]);

    return (
        <div className="w-full w-96 content-center">
            <div>
                編集画面
            </div>
            <form onSubmit={handleSubmit} className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" encType="multipart/form-data">
                <div className="userIdArea">
                    <input type="hidden" name="userId" value={targetEvent.userid || ''}/>                   
                </div>
                <div className="eventIdArea">
                    <input type="hidden" name="eventId" value={targetEvent.eventid || ''}/>
                </div>
                <div className="eventTitleArea">
                    <input
                        type="text"
                        name="eventTitle" 
                        defaultValue={targetEvent.eventtitle}
                        className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight"                                           
                    />
                    
                </div>
                <div className="eventDetailArea">
                    <textarea
                        name="eventDetail"
                        defaultValue={targetEvent.eventdetail}
                        className="block p-2.5 w-full text-sm text^gray-900 border border-gray-300"
                    ></textarea>
                </div>
                <div className="eventThumbnailArea">
                    <input type="file" 
                        name="eventThumbnailPath" 
                        defaultValue={targetEvent.eventthumbnailpath}
                        className="file-input file-input-bordered file-input-primary w-full"
                        />
                </div>
                <div className="eventEditArea">
                    <button type="submit" className="btn btn-primary" disabled={loading}>
                        {loading ? "更新中...":"更新する"}
                    </button>
                    <button className="btn btn-accent">クリアする</button>
                    <button className="btn btn-secondary" onClick={backToMyDashboard}>戻る</button>
                </div>
            </form>            
        </div>
    )
}
```
# サーバサイドのコードを解説する
プログラムのロジックは下記のようになっています。
<b>【手順】</b>
１．更新ボタンをクリックすると、アップロードしたい画像をプロジェクトの`public/uploads`フォルダに配置する
２．`public/uploads`フォルダに配置した画像の絶対パスを取得する
３．画像の絶対パスではブラウザに表示されないため、`http://localhost:3000/`のようにURLを用意してファイルパスを上書きする
４．イベント名、イベント内容、上書きした画像パスを`UPDATE文`でクエリ実行する
５．更新後、`ユーザーID`と`イベントID`を使ってレコードを取得する
６，対象レコードが取得できれば完了フラグ(True)を返却する

↑このような流れとなっています


```app/pages/api/editEvent.ts
'use server'

import { type NextRequest } from "next/server"
import { getDB } from "@/app/lib/db";
import { resolve } from "path";
import { promises as fs } from "node:fs";
import { buffer } from "stream/consumers";
import { revalidatePath } from "next/cache";

export default async function editTargetEvent(formData:FormData){
    //更新フラグを設定する
    let completeFlag = false;

    //フォームデータの値を取得する
    const userId = formData.get('userId');
    const eventId = formData.get('eventId');
    const eventTitle = formData.get('eventTitle');
    const eventDetail = formData.get('eventDetail');
    const eventThumbnailPath = formData.get('eventThumbnailPath') as File;
    const convertStringPathThumbnail = eventThumbnailPath?.toString();
    console.log("編集対象のユーザーIDは、" + userId);
    console.log("編集対象のイベントIDは、" + eventId);
    console.log("編集対象のイベントタイトルは、" + eventTitle);
    console.log("編集対象のイベント詳細は、" + eventDetail);
    console.log("編集対象のイベントパスは、" + convertStringPathThumbnail);

    //新規ファイルをアップロードする
    let filePath = '';
    if(eventThumbnailPath && eventThumbnailPath.size > 0){
        const data = await eventThumbnailPath.arrayBuffer();
        const buffer = Buffer.from(data);
        filePath = resolve(
            process.cwd(),
            "./public/uploads",
            `${eventThumbnailPath.name}`
        )
        await fs.writeFile(filePath,buffer);
        filePath = `http://localhost:3000/uploads/` + `${eventThumbnailPath.name}`;
    }
    revalidatePath("/file");
    
    //データベースと接続する
    const connection = await getDB();
    try{
        await connection.execute(`UPDATE eventInfo SET eventtitle = ? , eventdetail = ? , eventthumbnailpath = ? WHERE userid = ? AND eventid = ?`,
            [eventTitle,eventDetail,filePath,userId,eventId]
        );
        //データベースからの接続を停止する。
        //connection.end();
        console.log("データ挿入しました");
        const targetEditEvent = await connection.query(`SELECT * FROM eventInfo WHERE userid = ? AND eventid = ?`,[userId,eventId]);
        console.log("更新したイベント情報は、" + targetEditEvent);
        if(targetEditEvent.length > 0){
            console.log("イベントの更新に成功しました。");
            completeFlag = true;
            return completeFlag;
        }               
        
    }catch(error){
        console.log("イベント登録できませんでした。");
    }finally{
        connection.end();
    }
    return completeFlag;
}


```

参考になれば幸いです(^^♪