Open7

Laravel + Inertia + Reactのキャッチアップ

nakajimanakajima

概要

Laravel + Inertia + Reactのキャッチアップをした際のメモ
キャッチアップ理由は業務で触る必要性が出てきたので

sterter kitのコード見たり適当にいじったりしてキャッチアップを行う

私のレベル

laravelは8 - 9 あたりをキャッチアップしたことあり
reactはチョットワカル

なのでlaravelに関してもこれからキャッチアップする
laravelの情報もこのスクラップに入ってくる

関連技術の公式サイト

https://laravel.com/docs/12.x/starter-kits
https://inertiajs.com/

環境

  • Windows11
  • WSL Ubuntu 22.04
  • Laravel Installer 5.18.0
  • Laravel Framework 12.31.1
  • inertiajs/inertia-laravel v2.0.9
  • react 19.1.1
nakajimanakajima

インストール

docker使うことを検討したがめんどくさいのでローカルにphpとかインストールして環境構築

php インストール

sudo apt install php-cli unzip curl -y

composer インストール

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'ed0feb545ba87161262f2d45a633e34f591ebb3381f2e0063c345ebea4d228dd0043083717770234ec00c5a9f9593792') { echo 'Installer verified'.PHP_EOL; } else { echo 'Installer corrupt'.PHP_EOL; unlink('composer-setup.php'); exit(1); }"
php composer-setup.php
php -r "unlink('composer-setup.php');"

https://getcomposer.org/download/

laravel インストール

composer global require laravel/installer

https://laravel.com/docs/12.x/installation

laravel/installerのバージョンが古いのでアップデート
死んだはずのbreezeが選択肢に出てきて気が付いた

なんで最初から最新バージョン入らないんですかね...
laravel8を過去に触ったことあってドキュメントを一通り読んだから気が付けたけど初めて触る人は気が付けないでしょ

以下でアップデートして解決

composer global update laravel/installer

選択肢からbreezeとかが表示されなくなったことで成功を確認

❯ laravel new 2025-inertia-react-practice

   _                               _
  | |                             | |
  | |     __ _ _ __ __ ___   _____| |
  | |    / _` |  __/ _` \ \ / / _ \ |
  | |___| (_| | | | (_| |\ V /  __/ |
  |______\__,_|_|  \__,_| \_/ \___|_|


 ┌ Which starter kit would you like to install? ────────────────┐
 │ › ● None                                                     │
 │   ○ React                                                    │
 │   ○ Vue                                                      │
 │   ○ Livewire                                                 │
 └──────────────────────────────────────────────────────────────┘

マジでBladeが選択肢から無くなったんだ...
Reactとかのリッチな表現無くても良いサイトの需要は今もあるだろうけどそれらは範囲外にしたのかな?

nakajimanakajima

セットアップ

React使いたいのでReact使う
それ以外は一番上の選択肢を使う

 ┌ Which starter kit would you like to install? ────────────────┐
 │ React                                                        │
 └──────────────────────────────────────────────────────────────┘

 ┌ Which authentication provider do you prefer? ────────────────┐
 │ Laravel's built-in authentication                            │
 └──────────────────────────────────────────────────────────────┘

 ┌ Which testing framework do you prefer? ──────────────────────┐
 │ Pest                                                         │
 └──────────────────────────────────────────────────────────────┘

npm installしてくれる選択肢出てきたけどpnpm使いたいので辞めた

 ┌ Would you like to run npm install and npm run build? ────────┐
 │ No                                                           │
 └──────────────────────────────────────────────────────────────┘

pnpm iからpnpm buildを実行
それから以下を実行

composer run dev

http://localhost:8000 で起動確認

nakajimanakajima

ルーティング

初期のroutes/web.php

<?php

use Illuminate\Support\Facades\Route;
use Inertia\Inertia;

Route::get('/', function () {
    return Inertia::render('welcome');
})->name('home');

Route::middleware(['auth', 'verified'])->group(function () {
    Route::get('dashboard', function () {
        return Inertia::render('dashboard');
    })->name('dashboard');
});

require __DIR__.'/settings.php';
require __DIR__.'/auth.php';

return Inertia::render('welcome');resources/js/pages/welcome.tsx にルーティングされる

/から/loginに移動したときの通信

SPA的にHTMLのページ遷移は発生していないけど必要なデータはページ遷移したときに取りに行っているっぽい
routes/auth.phpの以下が実行され

    Route::get('login', [AuthenticatedSessionController::class, 'create'])
        ->name('login');

app/Http/Controllers/Auth/AuthenticatedSessionController.phpで以下のように書かれている


    public function create(Request $request): Response
    {
        return Inertia::render('auth/login', [
            'canResetPassword' => Route::has('password.request'),
            'status' => $request->session()->get('status'),
        ]);
    }

ルートの書き方は大きく分けて2つ

  1. 直接tsxを呼ぶ → return Inertia::render('welcome');
  2. コントローラーを介してtsxを呼ぶ → Route::get('login', [AuthenticatedSessionController::class, 'create'])しておいてコントローラで return Inertia::render('auth/login'
nakajimanakajima

Controllerから値を受け取る

page componentの場合

ルーティングで指定されるページコンポーネントの場合はpropsで受け取れる
以下がコントローラーのコード

class AuthenticatedSessionController extends Controller
{
    /**
     * Show the login page.
     */
    public function create(Request $request): Response
    {
        return Inertia::render('auth/login', [
            'canResetPassword' => Route::has('password.request'),
            'status' => $request->session()->get('status'),
        ]);
    }

renderの第2引数に連想配列で渡せばそれをpropsとして受け取れる

interface LoginProps {
    status?: string;
    canResetPassword: boolean;
}

export default function Login({ status, canResetPassword }: LoginProps) {
nakajimanakajima

認証情報の取得

Shared dataという仕組みで可能
https://inertiajs.com/shared-data

starter kitのコードで言うと以下
app/Http/Middleware/HandleInertiaRequests.php

    public function share(Request $request): array
    {
        [$message, $author] = str(Inspiring::quotes()->random())->explode('-');

        return [
            ...parent::share($request),
            'name' => config('app.name'),
            'quote' => ['message' => trim($message), 'author' => trim($author)],
            'auth' => [
                'user' => $request->user(),
            ],
            'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
        ];
    }

react側は usePage というフックで取得可能

export function AppShell({ children, variant = 'header' }: AppShellProps) {
    const isOpen = usePage<SharedData>().props.sidebarOpen;

    if (variant === 'header') {
        return (
            <div className="flex min-h-screen w-full flex-col">{children}</div>
        );
    }

    return <SidebarProvider defaultOpen={isOpen}>{children}</SidebarProvider>;
}
nakajimanakajima

ミドルウェア

定義はbootstrap/app.php

<?php

use App\Http\Middleware\HandleAppearance;
use App\Http\Middleware\HandleInertiaRequests;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->encryptCookies(except: ['appearance', 'sidebar_state']);

        $middleware->web(append: [
            HandleAppearance::class,
            HandleInertiaRequests::class,
            AddLinkHeadersForPreloadedAssets::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

Shared dataで使っていたミドルウェアもapp.phpで設定されている

authとか guest とかはデフォルトで用意されているミドルウェアなのでここにはない
https://laravel.com/docs/12.x/middleware