14 人が閲覧(直近 30 日) Laravel

Livewire(Laravel)とは?v4.4の使い方・コンポーネント作成とv3からの移行点

Livewire(Laravel)とは?v4.4の使い方・コンポーネント作成とv3からの移行点

Livewireは、LaravelのPHPクラスとBladeだけで、ページを再読み込みせずに動く画面を作るためのフレームワークです。入力と同時に絞り込まれる検索欄や、送信後にその場でエラーを出すフォームを、JavaScriptをほぼ書かずに実装できます。現行版は2026年10月21日公開のv4.4.8で、2026年1月のv4.0.0から単一ファイルコンポーネントが標準になりました。v2・v3時代の解説どおりに書くと、v4ではコンポーネントが見つからない、入力が反映されないといった不具合になります。この記事では、PHP 8.5.8・Laravel 13.39.0・Livewire 4.4.8の環境でコマンドとテストを実際に動かした結果をもとに、導入からコンポーネント作成、データバインディング、テスト、旧版からの移行までを解説します。

まとめ:Livewire 4の要点と採用の目安

  • 現行はv4.4.8(2026年10月21日)。動作要件はPHP 8.1以上、Laravel 10〜13。v3系もv3.8.11まで修正版が出ています。
  • 導入はcomposer require livewire/livewireだけ。CSSとJavaScriptはLivewireコンポーネントを含むページへ自動で挿入されます。
  • php artisan make:livewire counterは、resources/views/components/⚡counter.blade.phpに、クラスとテンプレートを1ファイルにまとめた単一ファイルコンポーネントを作ります。
  • wire:modelは入力のたびにはサーバーへ送りません。入力と同時に反映するならwire:model.live、離れたときに送るならwire:model.live.blurです(v4.1.0で.blur単独の意味が変わりました)。
  • 全ページ表示はRoute::livewire('/todo', 'pages::todo')。テストはLivewire::test()でブラウザなしに書けます。
  • Laravel中心のチームが作る管理画面・業務フォームに向きます。ネットワーク往復を待てない操作が主役の画面はVueやReactを選びます。

LivewireがLaravelで画面を更新する仕組み

サーバーで状態を持ち、変わった部分だけ書き換える動き

Livewireのコンポーネントは、PHPのプロパティに状態を持ちます。ボタンを押すと、ブラウザ側のLivewireが現在の状態(スナップショット)と操作内容をサーバーへPOSTし、サーバーはコンポーネントを復元してメソッドを実行し、Bladeを描画し直して返します。ブラウザはその結果と今のDOMを比べ、違う部分だけを書き換えます。実測で返ってきたHTMLにも、各コンポーネントの要素にwire:snapshotとwire:idの属性が付いていました。

この方式の代償は、操作のたびにネットワークを1往復することです。v4ではwire:model.liveの更新が並列に送られ、wire:pollが他のリクエストを止めなくなりましたが(公式アップグレードガイド)、往復そのものは無くなりません。

Vue・React・Inertia・Alpine.jsとの使い分け

Livewireは状態をサーバーに、VueやReactはブラウザに置きます。ドラッグ操作に追従するエディタや、オフラインでも動く画面はブラウザ側で状態を持つほうが向きます。InertiaはVueやReactを表示に使いながら、Laravelのルーティングとコントローラーでデータを渡す方式で、APIを別に作らずにSPAを組めます(Laravel Inertiaとは|APIを作らずSPAを組む仕組みと3系の変更点)。Alpine.jsはLivewireに同梱されているブラウザ側の小さなライブラリで、ドロップダウンの開閉のようにサーバーへ問い合わせる必要がない操作を受け持ちます(Alpine.jsとは?18ディレクティブの実装とCSP対応・採用判断を解説)。

Livewire 4の版の流れと現行版

v4は2026年1月14日のv4.0.0以降、機能追加と不具合修正のリリースが続いています。日付はPackagistの公開日です。

版 公開日 主な変更
v3.0.0 2023-08-24 名前空間App\Livewire・dispatch
v4.0.0 2026-01-14 単一ファイル標準・Islands
v4.1.0 2026-01-27 wire:model修飾子の変更
v4.2.0 2026-02-26 更新リクエストの防御強化
v4.3.0 2026-05-01 #[Authorize]属性
v4.4.0 2026-08-10 assertOnlyHasErrors
v4.4.8 2026-10-21 現行版

v4.2.0では、更新リクエストにX-LivewireヘッダーとJSONのContent-Typeを必須にし、mountなどのライフサイクルメソッドをブラウザから呼べないようにしました。v4.3.0の#[Authorize('update', 'post')]は、アクションの実行前にLaravelのGateで権限を確かめ、許可が無ければ403を返します(#[Authorize]の公式解説)。

v4で加わった単一ファイルコンポーネント・Islands・deferの遅延読み込み

v4の中心は、PHPのクラスとBladeを1つの.blade.phpに書く単一ファイルコンポーネントです。テンプレートの一部を@island〜@endislandで囲むと、その範囲だけを独立して再描画できます(Islandsの公式解説)。並べ替えのwire:sortもv4で加わりました。遅延読み込みはv3からあり、<livewire:revenue lazy />と書くと画面に入ったときに描画されます。v4ではこれに、ページ読み込みの直後に描画するdeferが加わりました(遅延読み込みの公式解説)。wire:transitionはブラウザ標準のView Transitions APIを使う実装に置き換わり、.opacityなどの修飾子が無くなりました。リンクに付けて全体の再読み込みなしにページを移るwire:navigateや、ブラウザ側で表示を切り替えるwire:show・wire:textはv3からある機能です。

検索で「livewire blaze」と一緒に調べられるBladeの高速化ツールBlazeは、Livewire本体には含まれていません。livewire/livewire 4.4.8の依存パッケージにも入っておらず、composer require livewire/blaze:^1.0で別に入れ、匿名Bladeコンポーネントの先頭に@blazeを書いてからphp artisan view:clearでコンパイル済みのビューを消すと有効になります(BlazeのREADME・現行v1.0.20)。

Livewireのインストール手順と対応環境(PHP 8.1以上・Laravel 10〜13)

既存のLaravelプロジェクトでComposerから追加します。パッケージの自動検出が働くので、サービスプロバイダーの登録は要りません。

composer require livewire/livewire
php artisan livewire:layout

livewire:layoutは、全ページ表示に使うresources/views/layouts/app.blade.phpを作ります。生成されたファイルには@livewireStylesと@livewireScriptsが入っていますが、無くても動きます。2つのディレクティブを消したレイアウトでページを返したところ、</body>の前にlivewire.jsを読む<script>タグが自動で挿入されていました(公式インストール手順も自動注入を明記)。すべてのページで自動注入を止めるにはconfig/livewire.phpのinject_assetsをfalseにし、レイアウトに2つのディレクティブを書きます。LivewireとAlpine.jsを自前のJavaScriptにまとめてビルドする場合は、@livewireScriptsの代わりに設定だけを出力する@livewireScriptConfigを置きます。

注意点は更新リクエストの送信先です。v3の/livewire/updateはv4で/livewire-{hash}/updateに変わり、実測でも/livewire-の後ろに8桁の英数字が付いたパスでした。Webサーバーやファイアウォールで/livewire/updateを名指しで許可していた場合は、設定を見直す必要があります。アセットをViteでまとめる構成にするときはLaravel Viteとは?使い方・@viteの書き方と本番ビルドの落とし穴【Laravel 13実測】も参照してください。

make:livewireによるコンポーネント作成

単一ファイルコンポーネント(v4の既定)の中身

php artisan make:livewire counterを実行すると、resources/views/components/⚡counter.blade.phpが1つだけ作られます。ファイル名の⚡は、通常のBladeコンポーネントと見分けるための印で、タグやルートで呼ぶ名前はcounterのままです。生成直後の中身は、無名クラスと空の<div>でした。カウンターにすると次のようになります。

<?php

use Livewire\Component;

new class extends Component
{
    public int $count = 0;

    public function increment(): void
    {
        $this->count++;
    }
};
?>

<div>
    <h1>{{ $count }}</h1>
    <button wire:click="increment">+</button>
</div>

テンプレートのルートは1つの要素にまとめます。publicプロパティはそのままBladeで参照でき、wire:clickに書いたメソッドがサーバー側で実行されます。

–class・–mfcとの使い分け

形式はコマンドのオプションで選びます(コンポーネントの公式解説)。

コマンド 生成されるファイル
make:livewire post.create components/post/⚡create.blade.php
make:livewire post.create –mfc components/post/⚡create/ 配下
make:livewire post.create –class app/Livewire/Post/Create.php ほか
make:livewire pages::todo pages/⚡todo.blade.php

--classでは、v3と同じApp\Livewire\Post\Createクラスとresources/views/livewire/post/create.blade.phpの2ファイルができました。ロジックが長くなり、PHPファイルとして静的解析やIDEの補完を効かせたいコンポーネントはクラス形式、画面ごとの小さなコンポーネントは単一ファイル、JavaScriptやCSSも同じ場所に置きたいなら複数ファイル形式(--mfc)が向きます。作った後でもphp artisan livewire:convert post.create --mfcで形式を変えられます。Laravel全体の生成コマンドはphp artisan makeコマンド一覧|Laravel 13対応 全37種の生成先・オプション早見表にまとめています。

Bladeへの埋め込みと全ページコンポーネントのルーティング

既存のBladeに部品として置くときは、コンポーネント名をタグにします。v4ではスロットに対応したため、タグを閉じないと後ろの内容がスロットとして扱われ、コンポーネントが表示されません。必ず<livewire:counter />のように閉じます。

コンポーネントを1ページとして表示するには、routes/web.phpにRoute::livewire()で登録します。この例では、ページ用のファイルをresources/views/pagesに分けて置くためpages::を付けて作っています。pages::は整理のための名前空間で、付けないコンポーネントもページにできます。

php artisan make:livewire pages::todo

// routes/web.php
Route::livewire('/todo', 'pages::todo');

ページはresources/views/layouts/app.blade.phpのレイアウトに差し込まれます。v4の設定キーはcomponent_layoutで、既定値はlayouts::appです。v3で使っていたRoute::get('/dashboard', Dashboard::class)もクラス形式なら動きますが、単一ファイル・複数ファイル形式をページにするにはRoute::livewire()が必要です。

wire:modelとアクションによるフォームの更新

wire:modelの同期タイミング(.live・.blur・.live.blur)

wire:modelは入力欄とプロパティを結び付けますが、既定では入力のたびにはサーバーへ送りません。値が送られるのは、wire:submitやwire:clickなどのアクションが走ったときです。v4.1.0では.blur・.change・.enterの意味が変わり、「ブラウザ側の値を同期するタイミング」だけを決めるようになりました(v4.1.0のリリースノート)。v3のように離れた瞬間にサーバーへ送りたいなら.liveを足します。

書き方 サーバーへ送る時点
wire:model 次のアクション実行時
wire:model.live 入力のたび(既定150msの間引き)
wire:model.live.debounce.300ms 入力が300ms止まったとき
wire:model.blur 次のアクション実行時
wire:model.live.blur 入力欄から離れたとき
wire:model.lazy changeイベント時(v3互換)

v4.0以前の記事にあるwire:model.blurをそのまま使うと、欄から離れてもサーバー側のバリデーションが走りません(wire:modelの公式解説)。もう1つの変更として、wire:modelは子要素から上がってくるイベントを受けなくなりました。モーダルのdivなどに付けて中の入力を拾っていた場合は.deepを足します。

wire:submitと#[Validate]による入力検証

プロパティに#[Validate]属性でルールを書き、アクションの中で$this->validate()を呼びます。エラーは通常のBladeと同じ@errorで出せます。

<?php

use Livewire\Attributes\Validate;
use Livewire\Component;

new class extends Component
{
    #[Validate('required|min:3')]
    public string $title = '';

    public array $todos = [];

    public function add(): void
    {
        $this->validate();
        $this->todos[] = $this->title;
        $this->reset('title');
    }
};
?>

<div>
    <form wire:submit="add">
        <input type="text" wire:model="title">
        @error('title') <span>{{ $message }}</span> @enderror
        <button type="submit">追加</button>
    </form>
    <ul>
        @foreach ($todos as $todo)
            <li wire:key="{{ $loop->index }}">{{ $todo }}</li>
        @endforeach
    </ul>
</div>

ループで並べる要素にはwire:keyを付けます。付けないと、要素の追加や削除の後にLivewireが差分の対応を取り違え、入力値や表示がずれることがあります。

リアルタイム検索の実装(#[Url]・#[Computed]・wire:loading)

入力と同時に一覧を絞り込む検索欄は、wire:model.liveと算出プロパティで作れます。php artisan make:livewire user-searchで作ったresources/views/components/⚡user-search.blade.phpを次の内容にし、画面には<livewire:user-search />で置きます。#[Url(as: 'q')]を付けると検索語が?q=としてURLに残り、共有したURLを開くと同じ結果が出ます。

<?php

use App\Models\User;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Url;
use Livewire\Component;

new class extends Component
{
    #[Url(as: 'q')]
    public string $search = '';

    #[Computed]
    public function users()
    {
        return User::query()
            ->when($this->search !== '', fn ($q) => $q->where('name', 'like', "%{$this->search}%"))
            ->orderBy('name')
            ->limit(20)
            ->get();
    }
};
?>

<div>
    <input type="search" wire:model.live.debounce.300ms="search" placeholder="名前で検索">
    <div wire:loading>検索中...</div>
    <ul>
        @forelse ($this->users as $user)
            <li wire:key="{{ $user->id }}">{{ $user->name }}</li>
        @empty
            <li>該当するユーザーはいません</li>
        @endforelse
    </ul>
</div>

#[Computed]の結果はテンプレートから$this->usersで参照し、同じリクエストの中では1回しか計算されません。検索結果をpublicプロパティに入れず算出プロパティにしているのは、publicプロパティがスナップショットとしてリクエストのたびにブラウザとサーバーの間を往復するためです。debounce.300msは、1文字ごとに検索を走らせないための間引きです。

Livewire::testによるコンポーネントのテスト

Livewireのコンポーネントは、ブラウザを起動せずにPHPUnitやPestからテストできます。この記事のカウンター・ToDo・検索の3コンポーネントに計5テストを書き、php artisan testで5テスト・18アサーションがすべて通りました(Laravel 13.39.0の既定のSQLiteインメモリ設定)。次はそのうち3テストを1ファイルにまとめたもので、tests/Feature/LivewireExampleTest.phpに置けばこのまま実行できます(単独で3テスト・11アサーション成功)。

<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;

class LivewireExampleTest extends TestCase
{
    use RefreshDatabase;

    public function test_todo_validation_and_add(): void
    {
        Livewire::test('pages::todo')
            ->set('title', 'ab')
            ->call('add')
            ->assertHasErrors(['title' => 'min'])
            ->set('title', '牛乳を買う')
            ->call('add')
            ->assertHasNoErrors()
            ->assertSet('title', '')
            ->assertSee('牛乳を買う');
    }

    public function test_query_string_initializes_search(): void
    {
        User::factory()->create(['name' => '佐藤 花子']);
        User::factory()->create(['name' => '鈴木 一郎']);

        Livewire::withQueryParams(['q' => '鈴木'])
            ->test('user-search')
            ->assertSet('search', '鈴木')
            ->assertSee('鈴木 一郎')
            ->assertDontSee('佐藤 花子');
    }

    public function test_page_route_renders(): void
    {
        $this->get('/todo')->assertOk()->assertSeeLivewire('pages::todo');
    }
}

set()はサーバー側のプロパティを書き換えるだけで、.liveやdebounceといったブラウザ側の送信タイミングまでは確かめません。call()はボタン操作に当たるメソッド呼び出しを再現します。#[Url]のプロパティはwithQueryParams()で初期値を渡すと、URLから復元される動きまで確かめられます。v4.4.0で入ったassertOnlyHasErrors()は、指定した項目以外にエラーが出ていないことまで確認します(テストの公式解説)。Pestで書く場合の導入はPestPHPとは?PHPUnitとの違い・導入手順と使い方|Pest 5.3を実測で解説を参照してください。

v2・v3のコードをv4へ移行するときに直す箇所

v2向けの記事やサンプルを写すと、v4では次のように失敗します。いずれもLivewire 4.4.8で実際に出たメッセージです。

  • App\Http\Livewire名前空間に置いたクラスを<livewire:old-counter />で呼ぶと、Unable to find component: [old-counter]になります。v3以降の置き場所はApp\Livewireです。
  • v2の$this->emit('pinged')はMethod App\Http\Livewire\OldCounter::emit does not exist.で止まります。イベントは$this->dispatch()で送ります。
項目 v2・v3 v4
クラスの名前空間 App\Http\Livewire(v2) App\Livewire
イベント送信 emit(v2) dispatch
wire:modelの既定 入力のたび(v2) アクション実行時
離れたときに送る wire:model.blur(v3) wire:model.live.blur
タグ 閉じなくても表示(v3) 閉じないと非表示
全ページのルート Route::get Route::livewire
レイアウト設定 layout component_layout
Volt Volt::route・Volt::test Route::livewire・Livewire::test

VoltはLivewire 3向けに単一ファイルの書き方を提供していたパッケージです。v4の単一ファイルコンポーネントは、Voltのクラスベース構文(new class extends Component)と同じ書き方です。公式のアップグレードガイドは、Livewire\Volt\ComponentをLivewire\Componentに置き換え、VoltServiceProviderを削除する手順を示しています。state()などを使う関数ベースのVoltコンポーネントはこの置き換えでは動かないため、サービスプロバイダーを消す前にクラスベースへ書き直します。livewire/voltは2026年7月31日のv1.11.2以降更新されておらず、新規の画面をVoltで書く理由はありません。

Livewireを採用すべき場面と避けるべき場面

採用すべきなのは、Laravelを書けるメンバーが中心で、画面の大半がフォーム・一覧・検索・管理画面であるプロジェクトです。EloquentのモデルとLaravelのバリデーションをそのまま画面に結び付けられるので、APIの設計とフロントエンドのビルドを分けて持つ手間が無くなります。管理画面を短期間で作るなら、Livewireの上に作られたFilamentも候補です(Laravel Filamentとは?管理画面を短工数で作る構成とNovaとの選択基準)。Laravel公式のスターターキットにもLivewire版があります(Laravel Breezeはなぜ非推奨に?Laravel 13で使う手順と後継スターターキット4種・移行判断)。

避けるべきなのは、次のような画面です。

  • ドラッグやキャンバス描画のように、操作のたびに画面が即座に追従しなければならない画面。操作のたびにネットワークの往復とサーバー処理の時間が待ちとして加わります。
  • モバイルアプリと同じAPIを共有する前提のサービス。Livewireを選んでもAPIは別に作ることになり、利点が薄れます。この場合はLaravelのAPIとReactなどの組み合わせが合います(LaravelとReactの連携方法|3つの構成の選び方とInertia・Sanctumの設定【Laravel 13】)。
  • 利用者が多く、1画面でwire:model.liveやwire:pollを多用する画面。リクエスト数がそのままサーバー負荷になるので、debounceやlazy、Islandsで更新範囲を絞る設計が前提になります。

Livewireを使った業務システムの設計や開発を外部に任せたい場合は、一創のフルスクラッチ開発でも対応しています。

よくある質問

Livewireの読み方と料金は?

「ライブワイヤー」と読みます。MITライセンスのオープンソースで、Composerから無料で導入できます。有料なのは、同じ開発元のUIコンポーネント集FluxのProプランなど周辺製品です。

Livewire 4はいつ公開され、現行版はいくつですか?

v4.0.0は2026年1月14日に公開されました。2026年10月29日時点の現行版は、10月21日公開のv4.4.8です。v3系も同じ日にv3.8.11が出ています。

wire:modelで入力と同時に画面へ反映するには?

wire:model.liveを使います。既定で150ミリ秒の間引きが入り、wire:model.live.debounce.300msのように長さを変えられます。入力欄から離れたときに送るなら、v4.1.0以降はwire:model.live.blurと書きます。

Livewire 4でVoltは必要ですか?

新しく書くコンポーネントには必要ありません。v4の単一ファイルコンポーネントはVoltのクラスベース構文と同じ書き方で、公式アップグレードガイドもVoltから本体への移行手順を載せています。関数ベースのVoltで書いた既存の画面は、移行前にクラスベースへ書き直します。

Livewire Blazeとは何ですか?

Livewireの開発元が出しているBladeコンポーネントの高速化パッケージlivewire/blazeです。Livewire本体には含まれず、composer require livewire/blaze:^1.0で入れてから、対象の匿名コンポーネントに@blazeを書き、php artisan view:clearを実行すると有効になります。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.11.04 テックブログ CVE-2026-119977:WordPress更新中のRCEと安全な更新手順
  2. 2026.11.03 テックブログ クラブツーリズム不正アクセス:約432万件の対象確認と偽メールの見分け方・流出検知の設計
  3. 2026.10.29 テックブログ ソニー生命の情報漏洩38.5万件|ログインできない理由、再開状況と窓口の電話番号
  4. 2026.10.31 テックブログ 松屋の不正アクセス:237万件の対象確認と窓口、漏れたパスワードの守り方
  5. 2026.11.05 テックブログ Linuxカーネルの脆弱性CVE-2026-98432:修正版の見分け方とnftablesの緩和策

RELATED POSTS 関連記事

目次