Menulis komponen Livewire dengan Volt: logika dan view dalam satu file .blade.php menggunakan anonymous class, integrasi dengan Folio untuk file-based routing, serta perbandingan kapan memilih class-based vs Volt.

Selama 18 episode kita menulis komponen dengan pola class-based: satu class PHP di app/Livewire/ dan satu view di resources/views/livewire/. Ada cara kedua yang lebih ringkas — Volt, functional API Livewire yang menaruh logika dan view dalam satu file .blade.php.
Volt bukan bahasa baru atau framework terpisah — ia tetap Livewire, hanya dengan sintaks yang lebih singkat. Bagi tim yang produktif menulis Blade, Volt menghilangkan dua-file syndrome untuk komponen kecil, dan bila digabung dengan Folio (file-based routing), kalian bisa membangun halaman penuh tanpa menulis route maupun class secara manual.
composer require livewire/volt
php artisan volt:installvolt:install membuat resources/views/livewire/volt.php (atau volt.blade.php) yang memberitahu Volt direktori mana yang berisi komponen functional.
Komponen Volt adalah satu file Blade dengan anonymous class di bagian atas:
<?php
use Livewire\Volt\Component;
new class extends Component {
public int $count = 0;
public function increment()
{
$this->count++;
}
};
?>
<div>
<h1>Jumlah: {{ $count }}</h1>
<button wire:click="increment">Tambah</button>
</div>Logika PHP (anonymous class) dan view berada di file yang sama. Cara render-nya sama seperti biasa:
<livewire:counter />Semua fitur yang kita pelajari tetap bekerja: wire:model, wire:click, lifecycle hooks, #[Computed], #[On], Form Objects, dan seterusnya. Vol hanya mengubah tempat dan cara menulis, bukan cara kerjanya.
Volt mendukung attribute dan hooks yang sama:
<?php
use Livewire\Attributes\Computed;
use Livewire\Attributes\On;
use Livewire\Attributes\Validate;
use Livewire\Volt\Component;
use App\Models\Post;
new class extends Component {
#[Validate('required|min:3')]
public string $title = '';
#[Computed]
public function posts()
{
return Post::latest()->get();
}
public function save()
{
$this->validate();
Post::create(['title' => $this->title]);
$this->dispatch('post-created');
}
#[On('post-created')]
public function flash()
{
session()->flash('status', 'Post dibuat.');
}
};
?>
<form wire:submit="save">
<input type="text" wire:model="title">
@error('title') <span>{{ $message }}</span> @enderror
<button type="submit">Simpan</button>
</form>Perhatikan: tidak ada namespace, tidak ada render(), tidak ada file terpisah. Komponen ini bisa langsung dirender sebagai full-page di route:
Route::get('/posts/create', \App\Livewire\CreatePost::class);...atau lebih ringkas lagi dengan Folio.
Folio adalah file-based routing Laravel: file di resources/views/pages/ otomatis menjadi halaman. Digabung dengan Volt, satu file menjadi satu halaman lengkap:
composer require laravel/folio
php artisan folio:install<?php
use Livewire\Volt\Component;
new class extends Component {
public int $visitors = 0;
public function refresh()
{
$this->visitors = Analytics::countToday();
}
};
?>
<div>
<h1>Dashboard</h1>
<p>Pengunjung hari ini: {{ $visitors }}</p>
<button wire:click="refresh">Muat ulang</button>
</div>Cukup menyimpan file di pages/dashboard.blade.php — halaman /dashboard langsung tersedia. Tidak ada route, tidak ada class PHP terpisah. Inilah alur tercepat untuk halaman admin/simple di Laravel.
Note
Volt dan class-based bisa hidup berdampingan dalam satu project. Aturan yang umum dipakai tim: halaman dan komponen kecil → Volt; komponen kompleks yang butuh diuji unit secara ekstensif → class-based. Tidak ada kewajiban memilih salah satu untuk seluruh aplikasi.
| Aspek | Class-based | Volt |
|---|---|---|
| File | Class PHP + view Blade | Satu file .blade.php |
| Struktur | namespace App\Livewire | Anonymous class |
| Kejelasan | Logika terpisah dari view | Logika dekat dengan markup |
| Testing | Livewire::test(Counter::class) | Livewire::test('counter') |
| Kompleksitas tinggi | Lebih mudah diorganisir | Mulai terasa sempit |
| Komponen kecil | Overhead dua file | Ideal |
Volt memenangkan kecepatan menulis dan kedekatan logika-tampilan. Class-based menang saat komponen besar dan membutuhkan organisasi ketat, injection dependensi eksplisit, atau pengujian unit yang intensif.
Panduan praktis:
Kuncinya: konsistensi per modul. Campurkan dua gaya dalam satu komponen yang sama hanya jika ada alasan kuat.
return: pastikan new class extends Component {...}; diakhiri titik koma, dan <?php ?> menutup sebelum markup Blade.wire:key, otorisasi, dst).volt:install dilewatkan: tanpa file pendaftar, Volt tidak tahu direktori mana yang berisi komponen.Inti yang harus dibawa pulang:
.blade.php memakai anonymous class.pages/*.blade.php menjadi satu halaman.Di episode 20 selanjutnya kita akan membahas testing komponen — Livewire::test() untuk memanggil action dan mengeset property, assertion seperti assertSee, assertHasErrors, assertDispatched, serta test CRUD dan alur form. Sampai jumpa di episode 20!