Reactのシンプルなサンプルをまとめているサイトはたくさんあるのですが、自分の環境に合っていない部分もあり、覚書のために本記事にまとめました。
本記事をまとめるにあたって、こちらの記事を参考にさせていただきました。
たいへん分かりやすくまとまっていて、こちらのサイトの情報だけでも完全に環境を構築することが出来ると思います。
Laravelで REST API を実装し Reactと連携したCRUDアプリ作成
https://qiita.com/masakichi_eng/items/af50d9a3e6a975b601e6
Laravel側
API作成
モデルとマイグレーションの作成
| 1 | $ php artisan make:model Product --migration | 
| 1 2 | INFO  Model [app/Models/Product.php] created successfully.   INFO  Migration [database/migrations/xxxx_xx_xx_xxxxxx_create_products_table.php] created successfully. | 
作成されたProductモデルに追記します。
app/Models/Product.php
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Product extends Model {     use HasFactory;     protected $fillable = [         'code',         'name',         'price',     ]; } | 
マイグレーションファイルを追記します。
database/migrations/xxxx_xx_xx_xxxxxx_create_products_table.php
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration {     /**      * Run the migrations.      */     public function up(): void     {         Schema::create('products', function (Blueprint $table) {             $table->id();             $table->string('code');             $table->string('name');             $table->integer('price');             $table->timestamps();         });     }     /**      * Reverse the migrations.      */     public function down(): void     {         Schema::dropIfExists('products');     } }; | 
マイグレーション実行
| 1 | $ php artisan migrate | 
| 1 2 | INFO  Running migrations.   xxxx_xx_xx_xxxxxx_create_products_table ........................................................................................ 2,335ms DONE | 
コントローラーの作成
| 1 | $ php artisan make:controller ProductController --api | 
いったん、コントローラーを作成し、実装は後ほど追記していきます。
| 1 | INFO  Controller [app/Http/Controllers/ProductController.php] created successfully. | 
ルーティング設定
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use App\Http\Controllers\ProductController; /* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider and all of them will | be assigned to the "api" middleware group. Make something great! | */ Route::middleware('auth:sanctum')->get('/user', function (Request $request) {     return $request->user(); }); Route::apiResource('/products', ProductController::class); | 
ルーティング確認
| 1 | $ php artisan route:list | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /var/www/html # php artisan route:list   GET|HEAD        / ...........................................................................................................................    POST            _ignition/execute-solution .................... ignition.executeSolution › Spatie\LaravelIgnition › ExecuteSolutionController   GET|HEAD        _ignition/health-check ................................ ignition.healthCheck › Spatie\LaravelIgnition › HealthCheckController   POST            _ignition/update-config ............................. ignition.updateConfig › Spatie\LaravelIgnition › UpdateConfigController   GET|HEAD        api/products ....................................................................... products.index › ProductController@index   POST            api/products ....................................................................... products.store › ProductController@store   GET|HEAD        api/products/{product} ............................................................... products.show › ProductController@show   PUT|PATCH       api/products/{product} ........................................................... products.update › ProductController@update   DELETE          api/products/{product} ......................................................... products.destroy › ProductController@destroy   GET|HEAD        api/user ....................................................................................................................    GET|HEAD        confirm-password ................................................. password.confirm › Auth\ConfirmablePasswordController@show   POST            confirm-password ................................................................... Auth\ConfirmablePasswordController@store   GET|HEAD        dashboard ......................................................................................................... dashboard   GET|HEAD        demo ............................................................................................ demo › DemoController@react   POST            email/verification-notification ...................... verification.send › Auth\EmailVerificationNotificationController@store   GET|HEAD        forgot-password .................................................. password.request › Auth\PasswordResetLinkController@create   POST            forgot-password ..................................................... password.email › Auth\PasswordResetLinkController@store   GET|HEAD        login .................................................................... login › Auth\AuthenticatedSessionController@create   POST            login ............................................................................. Auth\AuthenticatedSessionController@store   POST            logout ................................................................. logout › Auth\AuthenticatedSessionController@destroy   PUT             password ................................................................... password.update › Auth\PasswordController@update   GET|HEAD        profile ............................................................................... profile.edit › ProfileController@edit   PATCH           profile ........................................................................... profile.update › ProfileController@update   DELETE          profile ......................................................................... profile.destroy › ProfileController@destroy   GET|HEAD        register .................................................................... register › Auth\RegisteredUserController@create   POST            register ................................................................................ Auth\RegisteredUserController@store   POST            reset-password ............................................................ password.store › Auth\NewPasswordController@store   GET|HEAD        reset-password/{token} ................................................... password.reset › Auth\NewPasswordController@create   GET|HEAD        sanctum/csrf-cookie ....................................... sanctum.csrf-cookie › Laravel\Sanctum › CsrfCookieController@show   GET|HEAD        stock ......................................................................................... stock › StockController@index   GET|HEAD        verify-email ................................................... verification.notice › Auth\EmailVerificationPromptController   GET|HEAD        verify-email/{id}/{hash} ................................................... verification.verify › Auth\VerifyEmailController | 
コントローラーの実装
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Product; class ProductController extends Controller {     /**      * Display a listing of the resource.      */     public function index()     {         $products = Product::all();         return response()->json(             $products, 200         );     }     /**      * Store a newly created resource in storage.      */     public function store(Request $request)     {         $product = Product::create($request->all());         return response()->json(             $product, 201         );     }     /**      * Update the specified resource in storage.      */     public function update(Request $request, string $id)     {         $update = [             'code' => $request->code,             'name' => $request->name,             'quantity' => $request->quantity,         ];         $product = Product::where('id', $id)->update($update);         $products = Product::all();         if ($product) {             return response()->json(                 $products             , 200);         } else {             return response()->json([                 'message' => 'Product not found',             ], 404);         }     }     /**      * Remove the specified resource from storage.      */     public function destroy(string $id)     {         $product = Product::where('id', $id)->delete();         if ($product) {             return response()->json([                 'message' => 'Product deleted successfully',             ], 200);         } else {             return response()->json([                 'message' => 'Product not found',             ], 404);         }     } } | 
フォームリクエストバリデーション作成
| 1 | $ php artisan make:request StoreProduct | 
| 1 | INFO  Request [app/Http/Requests/StoreProduct.php] created successfully. | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Contracts\Validation\Validator; use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Validation\ValidationException; class StoreProduct extends FormRequest {     /**      * Determine if the user is authorized to make this request.      */     public function authorize(): bool     {         return true;     }     /**      * Get the validation rules that apply to the request.      *      * @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>      */     public function rules(): array     {         return [             'code' => 'required',             'name' => 'required',             'quantity' => 'required',         ];     }     /**      *       */     public function messages()     {         return [             'code.required' => 'コードが未入力です',             'name.required' => '名称が未入力です',             'quantity.required' => '数量が未入力です',         ];     }     /**      *       */     protected function failedValidation(Validator $validator)     {         $errors = (new ValidationException($validator))->errors();         throw new HttpResponseException(response()->json([             'message' => 'Failed validation',             'errors' => $errors,         ], 422, [], JSON_UNESCAPED_UNICODE));     } } | 
確認
curlコマンドでAPIを確認してみます。
新規作成
| 1 | $ curl -X POST http://localhost:8000/api/books  -d 'code=TEST00001&name=テスト商品1&price=1000' | 
すべてのレコードを確認
| 1 | $ curl http://localhost:8000/api/books/ | 
ブラウザで確認した場合には、このようにデータが表示されます。

React側
| 1 | $ npx create-react-app {プロジェクト名} --template typescript | 
React
Appコンポーネントを以下の記述に変更
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | import '../../../css/app.css'; import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; import { Head } from '@inertiajs/react'; import { useEffect, useState } from "react"; import axios from "axios"; export default function Stock(props) {     const [products, setProducts] = useState([         {             id: 0,             code: "",             name: "",             price: 0.         },     ]);     useEffect(() => {     axios         .get("http://localhost:8000/api/products/")         .then((response) => setProducts(response.data))         .catch((error) => console.log(error));     }, []);     const [code, setCode] = useState("");     const handleCodeChange = (e) => {       setCode(e.target.value);     };     const [name, setName] = useState("");     const handleNameChange = (e) => {       setName(e.target.value);     };     const [price, setPrice] = useState("");     const handlePriceChange = (e) => {       setPrice(e.target.value);     };     const createNewProduct = () => {         axios           .post("http://localhost:8000/api/products/", {             code: code,             name: name,             price: price,           })           .then((response) => {             setProducts([...products, response.data]);           })           .then(() => {             setCode("");             setName("");             setPrice("");           })           .catch((error) => {             console.log(error);           });       };       const deleteBook = (id) => {         axios           .delete(`http://localhost:8000/api/products/${id}`)           .then((response) => {             console.log(response);             setBooks(books.filter((book) => book.id !== id));           })           .catch((error) => console.log(error));       };       const modifyBook = (id) => {         axios           .patch(`http://localhost:8000/api/products/${id}`, {             code: code,             name: name,             price: price,           })           .then((response) => {             setProducts(response.data);           })           .then(() => {             setCode("");             setName("");             setPrice("");           })           .catch((error) => console.log(error));       };     return (         <AuthenticatedLayout             auth={props.auth}             errors={props.errors}             header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Stock</h2>}         >             <Head title="Stock" />             <table>                 <thead>                     <tr>                         <th>コード</th>                         <th>商品名</th>                         <th>単価</th>                     </tr>                 </thead>                 <tbody>                 {products.map((product) => (                 <>                     <tr key={product.id}>                         <td>{product.code}</td>                         <td>{product.name}</td>                         <td>{product.price}</td>                     </tr>                 </>                 ))}                 </tbody>             </table>             <label>                 code                 <input value={code} onChange={handleCodeChange} />             </label>             <label>                 name                 <input value={name} onChange={handleNameChange} />             </label>             <label>                 price                 <input value={price} onChange={handlePriceChange} />             </label>             <br />             <button onClick={createNewProduct}>作成</button>         </AuthenticatedLayout>     ); } | 
実行結果
下記の画面のように、一覧表示、登録ができる画面が表示されます。
参考サイト
手順はこちらの記事を参考にさせていただきました。
Laravelで REST API を実装し Reactと連携したCRUDアプリ作成
https://qiita.com/masakichi_eng/items/af50d9a3e6a975b601e6
 
  
  
  
  
 
 
         
         
         
         
         
        
