カテゴリー: FrontEndBackEnd

Inertia使ってみた①

はじめに

以前Laravel Breezeをインストールした際にパッケージに含まれていたInertiaを使ってみたので簡単に紹介したいと思います。
今回はLaravel + Reactの組み合わせで使用しています。

Inertiaとは

バックエンドフレームワーク(Laravelなど)とフロントフレームワーク(VueやReact)の橋渡しの様な事を行うライブラリの様なもので、Laravelで言うBladeと同じ感覚でVueやReactを使用してのSPAが簡単に作成出来る様にするものです。
公式に「 it’s fine-tuned for Laravel」とあるので、特にLaravel利用を想定して作成されているようです。

ルーティング

Laravelのルーティングを通常通りそのまま使用出来ます。

web.php

// prefix指定して、name付け
Route::prefix('sample')->name('invoice')->group(function () {
    Route::get('/', [SampleController::class, 'index'])->name('Index');
});

LaravelからReactに値渡し

Bladeを使うのと同じ様に、使用するReactのコンポーネントを指定して利用する値を引数に指定するだけでLaravelからReatcに値を渡す事が出来ます。

 public function index(Request $request)
    {
        // Reactに渡す値
        $foo = 'foo';
        $bar = 'bar';

        // 第一引数にコンポーネント、第二引数に渡したい値を指定
        return Inertia::render('Sample/Index', [
            'foo' => $foo,
            'bar' => $bar
        ]);
    }

フロント側でconsole.logすると、Propsに渡っているのが確認出来ます。

例えばモデルのコレクションを渡して、一覧表示みたいな事が簡単に出来ます。
Laravel

public function index(Request $request)
    {
        // Reactに渡す値
        $foo = 'foo';
        $bar = 'bar';

        // モデル取得してReactに渡す
        $users = User::all();

        // 第一引数にコンポーネント、第二引数に渡したい値を指定
        return Inertia::render('Sample/Index', [
            'foo' => $foo,
            'bar' => $bar,
            'users' => $users
        ]);
    }

React
props.usersでpropsからユーザー一覧情報を取得しています

export default function Index(props) {

    console.log('props:', props)

    return (
        <AuthenticatedLayout
            auth={props.auth}
            header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Profile</h2>}
        >
            <Head title="Sample" />

            <div className="py-12">
               ユーザー一覧 <br/>
                {props.users.map((user, index) => {
                    return (
                        <div key={index}>{user.name}</div>
                    )
                })}
            </div>
        </AuthenticatedLayout>
    );
}

先程のPropsに含まれているauthなど他の値は、HandleInertiaRequestsミドルウェアで設定されている値です。
ここで設定した値は、常にPropsに含まれる様になるのでコンポーネント関係なくグローバルに値保持したい場合に利用できそうです。
デフォルトではログインユーザー情報を含むauth、バリデーションエラーなどを含むerrors、Laravelのnameルーティング情報を含むziggyの3つが設定されています。

class HandleInertiaRequests extends Middleware
{
    /**
     * The root template that is loaded on the first page visit.
     *
     * @var string
     */    protected $rootView = 'app';

    /**
     * Determine the current asset version.
     */    public function version(Request $request): string|null
    {
        return parent::version($request);
    }

    /**
     * Define the props that are shared by default.
     *
     * @return array<string, mixed>
     */    public function share(Request $request): array
    {
        // parent::share($request)の中で error が設定されてる。
        return array_merge(parent::share($request), [
            'auth' => [
                'user' => $request->user(),
            ],
            'ziggy' => function () use ($request) {
                return array_merge((new Ziggy)->toArray(), [
                    'location' => $request->url(),
                ]);
            },
        ]);
    }
}

レスポンス

初回

レスポンスを見てみると、初回のアクセス時はHTMLとアセット(JSやCSS)が返却されており、このHTMLにはReactマウント用のdivタグが含まれています。
このdivタグのdata-pageにpage objectと呼ばれるデータ群が含まれていて、レンダリングの際にバックエンドからフロントエンドに渡る様です。

page object

page objectは以下で構成されているデータ群。
component: 表示しているコンポーネント名
props: バックエンドから渡される値
url: 表示画面のURL
version: アセットのバージョン管理用の値

2回目以降

2回目以降のアクセスでは、リクエストヘッダーにX-Inertia: trueが含まれます。
このリクエストを検知するとInertiaの方でpage objectのみを含んだJSONレスポンスが返却されます。

リロード時

通常、Propsは常に全て渡されますが、定数系の値など、中には初回以降は必要ない値もあると思います。
クロージャーで書く事で、リロード時にこうした値をPropsに含めない用に設定する事が可能です。
DBアクセスを含む不要な値を含めない様にする事で表示速度パフォーマンスを高める事が期待できます。

例えば以下の場合だと、
レスポンスのpropsに、初回はusersfooが含まれ、リロード時はbarのみが含まれます。

Laravel

Propsに含める変数の取得方法をそれぞれ変更しています。

public function index(Request $request)
    {
        // 初回アクセス時に必ず含まれる
        // リロート時に含めるか選択出来る
        // 常に評価される
        $users = User::all();

        // 初回アクセス時に必ず含まれる
        // リロート時に含めるか選択出来る
        // 含める時のみ評価される
        $foo = function () {
            return 'foo';
        };

        // 初回アクセス時に含まれない
        // リロート時に含めるか選択出来る
        // 含める時のみ評価される
        $bar = Inertia::lazy(function () {
            return 'bar';
        });

        // 第一引数にコンポーネント、第二引数に渡したい値を指定
        return Inertia::render('Sample/Index', [
            'foo' => $foo,
            'bar' => $bar,
            'users' => $users
        ]);
    }

React

ボタンクリック時にリロードしています。
その際に、onlyでレスポンスに含めるPropsを指定しています。
router.reload({ only: ['bar'] })

import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import {Head, Link} from '@inertiajs/react';
import { router } from '@inertiajs/react'

export default function Index(props) {
    // リロード
    // barのみPropsに含める
    const reload = () => {
        router.reload({ only: ['bar'] })
    }

    return (
        <AuthenticatedLayout
            auth={props.auth}
            header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Profile</h2>}
        >
            <Head title="Sample" />

            <div className="py-12">
               ユーザー一覧 <br/>
                {props.users.map((user, index) => {
                    return (
                        <div key={index}>{user.name}</div>
                    )
                })}
            </div>

            <div>
                <button type="button" onClick={reload} className="bg-blue-500 text-white" >リロード</button>
            </div>
        </AuthenticatedLayout>
    );
}

結果、barのみ含まれています。

さいごに

ほとんどMPAを作る要領でSPAが作成出来ました。次回はもう少し実践的な内容について書いてみたいと思います。

おすすめ書籍

Yossy

シェア
執筆者:
Yossy
タグ: laravelphpReact

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前