---
title: "Livewire（Laravel）とは？v4.4の使い方・コンポーネント作成とv3からの移行点"
url: "https://www.issoh.co.jp/tech/details/4474/"
published: 2024-12-11
updated: 2026-10-29
categories: ["Laravel"]
publisher: "株式会社一創"
---

# 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`が他のリクエストを止めなくなりましたが（[公式アップグレードガイド](https://livewire.laravel.com/docs/4.x/upgrading)）、往復そのものは無くなりません。

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

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

## Livewire 4の版の流れと現行版

v4は2026年1月14日のv4.0.0以降、機能追加と不具合修正のリリースが続いています。日付は[Packagist](https://packagist.org/packages/livewire/livewire)の公開日です。

| 版      | 公開日        | 主な変更                       |
| ------ | ---------- | -------------------------- |
| 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\]の公式解説](https://livewire.laravel.com/docs/4.x/attribute-authorize)）。

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

v4の中心は、PHPのクラスとBladeを1つの`.blade.php`に書く単一ファイルコンポーネントです。テンプレートの一部を`@island`〜`@endisland`で囲むと、その範囲だけを独立して再描画できます（[Islandsの公式解説](https://livewire.laravel.com/docs/4.x/islands)）。並べ替えの`wire:sort`もv4で加わりました。遅延読み込みはv3からあり、`<livewire:revenue lazy />`と書くと画面に入ったときに描画されます。v4ではこれに、ページ読み込みの直後に描画する`defer`が加わりました（[遅延読み込みの公式解説](https://livewire.laravel.com/docs/4.x/lazy)）。`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](https://github.com/livewire/blaze)・現行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>`タグが自動で挿入されていました（[公式インストール手順](https://livewire.laravel.com/docs/4.x/installation)も自動注入を明記）。すべてのページで自動注入を止めるには`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実測】](/tech/details/3251/)も参照してください。

## 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との使い分け

形式はコマンドのオプションで選びます（[コンポーネントの公式解説](https://livewire.laravel.com/docs/4.x/components)）。

| コマンド                             | 生成されるファイル                         |
| -------------------------------- | --------------------------------- |
| 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種の生成先・オプション早見表](/tech/details/3759/)にまとめています。

## 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のリリースノート](https://github.com/livewire/livewire/releases/tag/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の公式解説](https://livewire.laravel.com/docs/4.x/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()`は、指定した項目以外にエラーが出ていないことまで確認します（[テストの公式解説](https://livewire.laravel.com/docs/4.x/testing)）。Pestで書く場合の導入は[PestPHPとは？PHPUnitとの違い・導入手順と使い方｜Pest 5.3を実測で解説](/tech/details/7255/)を参照してください。

## 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との選択基準](/tech/details/17125/)）。Laravel公式のスターターキットにもLivewire版があります（[Laravel Breezeはなぜ非推奨に？Laravel 13で使う手順と後継スターターキット4種・移行判断](/tech/details/10351/)）。

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

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

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

## よくある質問

### 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`を実行すると有効になります。

## 関連記事

- [Laravel Inertiaとは｜APIを作らずSPAを組む仕組みと3系の変更点](/tech/details/17149/)
- [Alpine.jsとは？18ディレクティブの実装とCSP対応・採用判断を解説](/tech/details/16008/)
- [Laravel Filamentとは？管理画面を短工数で作る構成とNovaとの選択基準](/tech/details/17125/)
- [Laravel Breezeはなぜ非推奨に？Laravel 13で使う手順と後継スターターキット4種・移行判断](/tech/details/10351/)
- [LaravelとReactの連携方法｜3つの構成の選び方とInertia・Sanctumの設定【Laravel 13】](/tech/details/2906/)

---

出典: [Livewire（Laravel）とは？v4.4の使い方・コンポーネント作成とv3からの移行点](<https://www.issoh.co.jp/tech/details/4474/>)（株式会社一創）
