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

概要
Laravel + Inertia + Reactのキャッチアップをした際のメモ
キャッチアップ理由は業務で触る必要性が出てきたので
sterter kitのコード見たり適当にいじったりしてキャッチアップを行う
私のレベル
laravelは8 - 9 あたりをキャッチアップしたことあり
reactはチョットワカル
なのでlaravelに関してもこれからキャッチアップする
laravelの情報もこのスクラップに入ってくる
関連技術の公式サイト
環境
- 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

インストール
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');"
laravel インストール
composer global require laravel/installer
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とかのリッチな表現無くても良いサイトの需要は今もあるだろうけどそれらは範囲外にしたのかな?

セットアップ
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
で起動確認

ルーティング
初期の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つ
- 直接tsxを呼ぶ →
return Inertia::render('welcome');
- コントローラーを介してtsxを呼ぶ →
Route::get('login', [AuthenticatedSessionController::class, 'create'])
しておいてコントローラでreturn Inertia::render('auth/login'

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) {

認証情報の取得
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>;
}

ミドルウェア
定義は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
とかはデフォルトで用意されているミドルウェアなのでここにはない