🦔

Inertia.js v2.0で追加された新機能を実際に実装してみた

に公開

概要

2週間前、Inertia.jsの2.0が正式にリリースされました。
今回のアップデート内容についてはこちらから確認することができます。
v2.0になって非同期リクエストの機能が大幅にサポートされました。
この記事では、新たに追加された以下の非同期リクエストの機能を実際に実装して動作とコードをまとめます。

  • Polling
  • Prefetching
  • Deferred props
  • Infinite scrolling
  • Lazy loading data on scroll

動作環境

  • Laravel11
  • Vue3

Pooling

サーバーに定期的に通信してpropsを更新してくれます。
例として、propsで現在時刻を受け取りフロントで描画する簡単なコードを書きました。

https://www.youtube.com/watch?v=KrnW-PLjiTc

Poolingのためのコードも非常にシンプルです。

<template>
    <h1>current time is {{props.currentTime}}</h1>
</template>

<script setup lang="ts">
import {usePoll} from "@inertiajs/vue3";

const props = defineProps({
    currentTime: {
        type: String,
        required: true,
    }
})

usePoll(1000);
</script>

Prefetching

ページにアクセスする前にサーバーに通信を行いpropsを取得してくれます。
サーバーに通信を行うタイミングはコンポーネントが'mount' or 'hover' or 'click' された時の3つから複数選択可能です。デフォルトだと 'hover' になります。
例では一覧として表示されたユーザーリストをクリックして、ユーザーの詳細情報を表示する画面に遷移しています。
この時、ユーザーの詳細情報を表示するAPIにわざと2s程度のSleepを入れてPrefetchingされている時とされていない時の挙動の違いをわかりやすくしています。

https://youtu.be/dO2dKzRRll4

import { Link } from '@inertiajs/vue3'

<Link href="/users" prefetch>Users</Link>

JavaScriptでハンドリングすることもできます。

router.prefetch(
    '/users',
    { method: 'get', data: { page: 2 } },
)

router.prefetch(
    '/users',
    { method: 'get', data: { page: 2 } },
    { cacheFor: '1m' },
)

もしくは、

import { usePrefetch } from '@inertiajs/vue3'

const { lastUpdatedAt, isPrefetching, isPrefetched } = usePrefetch(
    '/users',
    { method: 'get', data: { page: 2 } },
    { cacheFor: '1m' },
)

ここで、cacheという概念が登場します。
その名の通り、prefetchしたデータをキャッシュすることができます。
デフォルトでは、30secの間データがキャッシュされます。
cacheの時間は任意の時間に調整可能です。

Deferred props

特定のデータの読み込みをページレンダリングの後まで延期できます。
例では先にページのレンダリングを行い、レンダリング後にユーザーの詳細情報を取得しています。

https://youtu.be/ibHcFolG6t0

class DeferController extends Controller
{
    public function __invoke()
    {
        return Inertia::render('Example/Defer', [
            'user' => Inertia::defer(function() {
               Sleep::sleep(1);
               return User::where('id', 1)->first();
            }),
        ]);
    }
}
<template>
    <Deferred data="user">
        <template #fallback>
            <div>Loading...</div>
        </template>

        <div>
            <h1>user data</h1>
            <ul>
                <li>{{user['id']}}</li>
                <li>{{user['name']}}</li>
                <li>{{user['email']}}</li>
            </ul>
        </div>
    </Deferred>
</template>

<script setup>
import { Deferred } from '@inertiajs/vue3'

defineProps({
    user: {
        type: Object,
    }
})
</script>

Infinite scrolling

ドキュメントには Infinite scrolling と書かれている箇所もありますが、Merging props と書かれている箇所もあります。コード的にはpropsのマージです。

ただ、実際に試してみたところうまくinfinite scrollできませんでした。

リポジトリにバグ報告のissueが作成されており、バグの内容もこちらで再現した時と同じようだったのでissueが解決されればうまく機能すると思います。
https://github.com/inertiajs/inertia/issues/2068

Lazy loading data on scroll

コンポーネントが画面に表示された時にデータのリクエストを行う機能です。
例として水色の背景の箇所をスクロールするとサーバーから取得した文字が表示される実装をしてみました。

https://www.youtube.com/watch?v=liJ5TZn9ak0

ドキュメントには直接書いていませんが、サーバーサイドではPartialReloadsを使用してデータを渡さないとlazy-loadingになりません。

<?php

namespace App\Http\Controllers\Example;


use App\Http\Controllers\Controller;
use Illuminate\Support\Sleep;
use Inertia\Inertia;

class LoadWhenVisibleController extends Controller
{
    public function __invoke()
    {
        return Inertia::render('Example/LoadWhenVisible', [
            'message' => Inertia::lazy(function() {
                Sleep::sleep(2);
                return 'viewed!!';
            })
        ]);
    }
}
<template>
    <div class="load-when-visible">
        <h1>LoadWhenVisible</h1>

        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>

        <WhenVisible data="message">
            <template #fallback>
                <div>Loading...</div>
            </template>

            <div>
                <p>{{message}}</p>
            </div>
        </WhenVisible>
    </div>
</template>

<script setup>
import { WhenVisible } from '@inertiajs/vue3'
defineProps({
    message: {
        type: String,
    }
})
</script>

<style scoped>
.load-when-visible {
    width: 500px;
    height: 300px;
    background-color: deepskyblue;
    overflow: scroll;
}
</style>

所感

今までInertia.jsで非同期でデータを扱うにはPartialReloadsしか存在しないと個人的には認識しています。
PartialReloads以外だとSPAのようにAPIに対してアクセスする方法しかなく、"APIを構築しなくていい"というInertia.jsの利点を活かすことができませんでした。
今回、Inertia.jsの機能に乗りながら、非同期でデータを扱うことができるようになりました。
Inertia.jsの利点を活かしつつ、非同期でデータを扱うユースケース(大量のデータ,レンダリング時間の有効活用など)を行えるようになり、Inertia.jsが合致するビジネスケースが増えたと感じました。

GitHubで編集を提案

Discussion