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?

ReactとLaravel連携して一覧画面にデータを表示するまでの流れ

Posted at

サンプルイメージ

今回は、一覧画面にイベント情報を取得して表示するサンプルを作っていきます。

一覧画面.png

この画面を作るにあたり、TailwindCSSのCardコンポーネントを使用しました。

このアプリの関連記事

フロント(React)の画面作成

一覧画面

メンテナンス性の観点から
Cardコンポーネントは、別ファイルとして作成しています。

frontend/src/dashboard/page.tsx
import { useNavigate } from "react-router-dom"
import Navbar from "../components/navbar/page";
import axios from "axios";
import { useEffect, useState } from "react";
import Card from "../components/card/page";

export default function dashboard(){
    //ページナビゲータを用意する
    const navigate = useNavigate();
    const backToLogin = ()=>{
        navigate('/');
    }

    const[allEvent,setAllEvent] = useState<any[]>([]);        
    
    useEffect(()=>{
        const fetchEvents = async()=>{
            try{
                const response = await axios.get(
                    "http://localhost:8000/api/eventAllRead",
                    {
                        headers:{
                            'Cache-Control': 'no-cache', // キャッシュを無効化
                            Pragma: 'no-cache',
                        }
                    }
                
                );
                if(response.request.status === 200){
                    setAllEvent(response.data); // 正しいデータを取得
                }
            }catch(error){
                console.error("イベントの取得に失敗しました",error);
                alert("イベントの取得に失敗しました");
            }
        };
        fetchEvents();
    },[]);
    

    return (
        <div>
            <Navbar></Navbar>
            ダッシュボード
            {/*カードコンポーネント*/}
            <div className="cardArea grid grid-cols-3 gap-2">                                               
                {allEvent.length > 0 && allEvent.map((event)=>( 
                    <Card event={event} key={event.eventid}></Card>
                ))}                                                                                                            
            </div>
            <div>
                <button type="button" onClick={backToLogin} className="bg-blue-500 text-white font-bold px-4 py-4">
                    ログイン画面に戻る
                </button>
            </div>
        </div>
    )
} 

Cardコンポーネント

frontend/src/components/card/page.tsx
import { useNavigate } from "react-router-dom"

type Event = {
    id?:number;
    name:string;
    description:string;
    thumbnail_path:string
}

export default function Card({event}){
    //ルーティング設定
    const navigate = useNavigate();

    //更新ボタンプ家事の処理
    const EditEvent =()=>{
        navigate(`/event/eventEdition?id=${id}&name=${name}&description=${description}`);//navigate(`/event/eventEdition&id=${event.id}`);
    }

    const {id,name,description,thumbnail_path} = event;
    return (
        <div>                                   
            <div className="card bg-base-100 w-96 shadow-xl">
                <div style={{visibility:"collapse"}}>{id}</div>                               
                <div className="card bg-base-100 w-96 shadow-xl">              
                    <figure>
                        <img 
                            src={`http://localhost:8000${thumbnail_path}`} 
                            alt={name || "No Image"}
                            onError={(e)=>{
                                (e.target as HTMLImageElement).src = "/default-thumbnail.jpg";
                            }}
                        />
                    </figure>
                    <div className="card-body">
                        <h2 className="card-title font-bold text-xl mb-2">{name}</h2>
                        <p className="text-base">{description}</p>
                        <div className="card-action flex items-center justify-center mt-8">
                            <button className="bg-blue-500 text-white font-bold rounded-md px-4 py-4 mr-2" onClick={EditEvent}>
                                編集する
                            </button>
                            <button className="btn btn-accent text-white bg-rose-500 font-bold rounded-md px-4 py-4">
                                削除する
                            </button>
                        </div>                   
                    </div>
                </div>                
            </div>
        </div> 
    )
}

サーバ(Laravel)のコード作成

つづいて、サーバ側の作成していきます。
今回対象になるのは、下部にある下記のコードです。

backend/app/Http/Controllers/EventController.php
    public function readAllEvents()
    {
        $events = Event::orderBy('id','asc')->get(); // findAll()ではなくall()を使用
        return response()->json($events, 200)
                ->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
                ->header('Pragma', 'no-cache')
                ->header('Expires', 'Thu, 01 Jan 1970 00:00:00 GMT');
        /*
        return response()->json([
            $event
        ],200);
        */
    }

また、ID値が地井さん順に全件取得するのでクエリビルダーは下記のように書いても良いです。

sample.php
$events = Event::all()->orderBy('id', 'asc');;

全体のコードはこちら↓

backend/app/Http/Controllers/EventController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;//20250110追加
use App\Models\Event;//2025.01.10追加

class EventController extends Controller
{
    public function registerEvent(Request $request)
    {
        \Log::info('リクエストデータ:', $request->all());
        $request->validate([
            'eventName' => 'required|string|max:255',
            'eventDescription' => 'required|string|max:1000',
            'eventThumbnail' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
        ]);

        //元のファイル名を取得する
        $originalFileName = $request->file('eventThumbnail')->getClientOriginalName();
        //ファイル名が重複しないようにタイムスタンプを追加する。
        $fileName = time().'_'.$originalFileName;

        //カスタムファイル名で画像を保存する
        $imagePath = $request->file('eventThumbnail')->storeAs('public/event_thumbnails',$fileName);
        //公開URLを生成する
        $imageUrl = Storage::url($imagePath);

        //データベースに保存する
        $event = new Event();
        $event->name = $request->eventName;
        $event->description = $request->eventDescription;
        $event->thumbnail_path = $imageUrl;
        $event->save();

        return response()->json([
            'eventName' => $event->name,
            'eventDescription' => $event->description,
            'eventThumbnail' => $imageUrl,   
        ],200);
    }

    public function editEvent(Request $request){
        \Log::info('リクエストデータ:', $request->all());
        /*これは削除しておく
        $request->validate([
            'eventId' => 'required|integer',
            'eventName' => 'required|string|max:255',
            'eventDescription' => 'required|string|max:1000',
            'eventThumbnail' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048', // 画像は必須ではない場合
        ]);
                
        if ($validator->fails()) {
            return response()->json([
                'errors' => $validator->errors()
            ], 422);
        }
        */


        $targetId = $request->get('eventId');//$request->get('eventId')

        //画像ファイル処理
        $imageUrl = null;
        //$imageUrl = $request->file('eventThumbnail')->getClientOriginalName();
        
        if($request->hasFile('eventThumbnail')){
            
            //古い画像の削除
            if($imageUrl){
                // Storage::delete()で古い画像ファイルを削除
                $imagePath = public_path('storage') . '/' . basename($imageUrl); // 正しいパスに修正
                if (file_exists($imagePath)) {
                    unlink($imagePath);  // ファイル削除
                }
            }
            
            //元のファイル名を取得する
            $originalFileName = $request->file('eventThumbnail')->getClientOriginalName();
            //ファイル名が重複しないようにタイムスタンプを追加する。
            $fileName = time().'_'.$originalFileName;
            //カスタムファイル名で画像を保存する
            $imagePath = $request->file('eventThumbnail')->storeAs('public/event_thumbnails',$fileName);
            //公開URLを生成する
            $imageUrl = Storage::url($imagePath);

        }      

        //データベースの更新
        $event = Event::find($targetId);
        if (!$event) {
            return response()->json([
                'error' => 'イベントが見つかりません'
            ], 404);
        }

        $event->name = $request->eventName;
        $event->description = $request->eventDescription;
        $event->thumbnail_path = $imageUrl;
        if($imageUrl){
            $event->thumbnail_path = $imageUrl;
        }

        $event->save();
               
        return response()->json([
            'eventName' => $event->name,
            'eventDescription' => $event->description,
            'eventThumbnail' => $event->thumbnail_path,   
        ],200);
    }

    public function readAllEvents()
    {
        $events = Event::orderBy('id','asc')->get(); // findAll()ではなくall()を使用
        return response()->json($events, 200)
                ->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
                ->header('Pragma', 'no-cache')
                ->header('Expires', 'Thu, 01 Jan 1970 00:00:00 GMT');
        /*
        return response()->json([
            $event
        ],200);
        */
    }

}


以上です。

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?