Livewire adalah framework untuk membangun komponen halaman yang reaktif dengan logika yang tetap berjalan di server Laravel. Topik ini membahas model kerjanya, membangun satu komponen pencarian catatan pada aplikasi catatan, dan menunjukkan siklus permintaannya melalui keluaran nyata. Setelah membacanya, keputusan menggunakan atau tidak menggunakan Livewire untuk sebuah halaman dapat diambil dengan alasan teknis yang jelas.
Model kerja Livewire#
Sebuah komponen Livewire terdiri atas kelas PHP dan template Blade. Saat halaman pertama kali dibuka, Laravel merender template itu menjadi HTML utuh, persis seperti halaman Blade biasa. Halaman tetap lengkap meskipun JavaScript belum berjalan, sehingga konten awal tampil cepat dan mudah dibaca mesin pencari.
Perilaku dinamis muncul setelah skrip livewire.js dimuat. Pada template, atribut wire:model mengaitkan elemen masukan dengan properti publik kelas, sedangkan atribut wire:click memanggil metode kelas. Ketika pengguna mengetik atau menekan tombol, livewire.js mengirim permintaan ke endpoint pembaruan milik Livewire dengan membawa snapshot, yaitu data komponen yang diserialisasi beserta checksum pengamannya. Server membangun ulang kelas tersebut, memperbarui properti publiknya, menjalankan metode yang diminta, lalu merender ulang template menjadi HTML baru. Browser menerima HTML itu dan mengubah DOM lama menjadi DOM baru secara selektif, mekanisme yang disebut morphing, tanpa memuat ulang halaman.
Dengan model ini, seluruh keadaan komponen tersimpan di server. Browser hanya mengirim snapshot kecil dan menerima HTML, sehingga logika, validasi, dan akses database tidak pernah diturunkan ke sisi klien. Alur satu interaksi dirangkum pada diagram berikut.
Komponen pencarian catatan#
Livewire dipasang sebagai paket Composer, kemudian komponen dibuat dengan perintah Artisan. Kedua perintah berikut memerlukan koneksi jaringan dan menghasilkan berkas baru, sehingga tidak dieksekusi ulang di sini.
# tidak-dijalankan
# menginstal livewire ke proyek Laravel
cd ~/aplikasi-catatan
composer require livewire/livewireKeluaran sungguhan dari satu percobaan pemasangan pada salinan proyek berakhir dengan baris berikut.
82 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan vendor:publish --tag=laravel-assets --ansi --force
INFO No publishable resources for tag [laravel-assets].
No security vulnerability advisories found.
Using version ^4.4 for livewire/livewireLivewire 4 menyediakan dua bentuk komponen. Bentuk default adalah single-file component, yaitu satu berkas Blade berisi kelas anonim dan markahnya dengan nama seperti resources/views/components/⚡pencari-catatan.blade.php, sedangkan opsi --class menghasilkan kelas dan view yang terpisah. Bentuk kelas digunakan pada topik ini agar setiap berkas dapat dibahas tersendiri.
# tidak-dijalankan
# membuat komponen livewire berbasis kelas
cd ~/aplikasi-catatan
php artisan make:livewire PencariCatatan --class INFO Livewire component [app/Livewire/PencariCatatan.php] created successfully.Komponen yang dibahas adalah pencari catatan, yaitu kotak pencarian yang menyaring daftar catatan mengikuti kata kunci. Kelasnya dibuat pada berkas app/Livewire/PencariCatatan.php dengan isi berikut.
// tidak-dijalankan
<?php
namespace App\Livewire;
use App\Models\Note;
use Livewire\Component;
class PencariCatatan extends Component
{
public string $cari = '';
public function render()
{
return view('livewire.pencari-catatan', [
'catatan' => Note::with('category')
->where('judul', 'like', "%{$this->cari}%")
->orderBy('judul')
->get(),
]);
}
}Properti publik $cari menyimpan kata kunci pencarian. Sifat publik bukan pilihan gaya, melainkan kebutuhan mekanisme: hanya properti publik yang diserialisasi ke snapshot dan yang dapat diikat dari template. Metode render() menjalankan query model Note seperti pada controller biasa, termasuk pemuatan relasi kategori dengan with(). Templatenya dibuat pada berkas resources/views/livewire/pencari-catatan.blade.php.
<div>
<input type="search" placeholder="Cari judul catatan" wire:model.live="cari">
<p>{{ $catatan->count() }} catatan ditemukan.</p>
<ul>
@forelse ($catatan as $note)
<li wire:key="catatan-{{ $note->id }}">
{{ $note->judul }}
@if ($note->category)
— {{ $note->category->nama }}
@endif
</li>
@empty
<li>Tidak ada catatan yang cocok.</li>
@endforelse
</ul>
</div>Atribut wire:model.live mengikat kotak masukan ke $cari dan mengirim pembaruan ke server setiap kali isi masukan berubah. Atribut wire:key memberi identitas tetap pada setiap butir daftar sehingga proses morphing mencocokkan butir berdasarkan kuncinya, bukan berdasarkan posisinya. Komponen ini juga dapat dijadikan halaman penuh: kelasnya dipasang langsung sebagai aksi rute, dan Livewire merender hasilnya ke dalam sebuah layout.
// tidak-dijalankan
use App\Livewire\PencariCatatan;
Route::get('/cari', PencariCatatan::class);Layout untuk komponen halaman penuh dibuat dengan php artisan livewire:layout, yang menghasilkan resources/views/layouts/app.blade.php berisi pemanggilan {{ $slot }} serta @livewireScripts. Rute yang terdaftar dapat diperiksa dengan perintah berikut.
# tidak-dijalankan
# memeriksa rute komponen yang sudah terdaftar
cd ~/aplikasi-catatan
php artisan route:list --path=cariKeluaran sungguhan dari salinan proyek menunjukkan rutenya.
GET|HEAD cari ............................ App\Livewire\PencariCatatan
Showing [1] routesSiklus permintaan yang tampak di HTML#
HTML awal komponen dapat dirender tanpa browser melalui Tinker. Perintah berikut memanggil Livewire::mount(), yaitu fungsi yang sama yang digunakan framework saat halaman dimuat.
# tidak-dijalankan
# merender HTML awal komponen tanpa browser
cd ~/aplikasi-catatan
php artisan tinker --execute='
echo \Livewire\Livewire::mount("pencari-catatan");
'Keluaran sungguhan dari salinan proyek dengan tiga catatan seed adalah berikut.
<div wire:snapshot="{"data":{"cari":""},"memo":{"id":"7wFkBrikjqPYo764Fek2","name":"pencari-catatan","path":"\/","method":"GET","release":"a-a-a","children":[],"scripts":[],"assets":[],"errors":[],"locale":"en","islands":[]},"checksum":"618673ad99adb18c3d363dad6489065294d4cc8364079952f7a2d483cee17b27"}" wire:effects="[]" wire:id="7wFkBrikjqPYo764Fek2" wire:name="pencari-catatan">
<input type="search" placeholder="Cari judul catatan" wire:model.live="cari">
<p>3 catatan ditemukan.</p>
<ul>
<!--[if BLOCK]><![endif]--> <li wire:key="catatan-2">
Belajar Laravel Livewire
<!--[if BLOCK]><![endif]--> — Belajar
<!--[if ENDBLOCK]><![endif]--> </li>
<li wire:key="catatan-3">
Daftar belanja mingguan
<!--[if BLOCK]><![endif]--> — Pribadi
<!--[if ENDBLOCK]><![endif]--> </li>
<li wire:key="catatan-1">
Rapat koordinasi tim
<!--[if BLOCK]><![endif]--> — Kerja
<!--[if ENDBLOCK]><![endif]--> </li>
<!--[if ENDBLOCK]><![endif]--> </ul>
</div>Bagian penting terletak pada atribut pembuka. wire:snapshot membawa data komponen, di sini cari bernilai kosong, beserta identitas dan checksum-nya. checksum mencegah snapshot dimanipulasi dari sisi browser, sedangkan wire:id menandai instance komponen pada halaman itu. Bagian bawahnya adalah HTML biasa hasil render Blade. Nilai wire:id dan checksum berubah pada setiap render, sehingga keluaran persisnya berbeda dari contoh ini.
Interaksi dapat diuji tanpa browser menggunakan Livewire::test(), yang mengeksekusi komponen di dalam proses PHP.
# tidak-dijalankan
# menguji penyaringan komponen tanpa browser
cd ~/aplikasi-catatan
php artisan tinker --execute='
$hasil = \Livewire\Livewire::test(\App\Livewire\PencariCatatan::class);
$hasil->assertSee("Rapat koordinasi tim");
$hasil->set("cari", "bel");
$hasil->assertSee("Belajar Laravel Livewire");
$hasil->assertSee("Daftar belanja mingguan");
$hasil->assertDontSee("Rapat koordinasi tim");
echo "Tiga pernyataan lolos: daftar tersaring mengikuti kata kunci." . PHP_EOL;
'Pemanggilan set("cari", "bel") meniru ketikan pengguna, lalu setiap pernyataan memeriksa HTML hasil render ulang di server. Keluaran percobaan pada salinan proyek adalah berikut.
Tiga pernyataan lolos: daftar tersaring mengikuti kata kunci.Kapan Livewire cocok digunakan#
Livewire menawarkan titik tengah antara Blade murni dan aplikasi SPA. Rute, validasi, dan query tetap berada di kode PHP yang sama, tanpa API terpisah, sedangkan bagian dinamisnya cukup ditulis sebagai kelas dan template. Konsekuensinya ada pada jaringan: setiap interaksi menimbulkan permintaan ke server, sehingga halaman dengan animasi kaya khas SPA lebih tepat ditangani pendekatan Inertia.
| Kebutuhan halaman | Pendekatan yang lazim |
|---|---|
| Halaman informatif dengan interaksi minim | Blade biasa tanpa komponen dinamis |
| Formulir, pencarian, filter, dan daftar yang merespons masukan | Livewire |
| Antarmuka bergaya SPA dengan pustaka Vue atau React | Inertia |
Kesalahan umum#
Kesalahan pertama adalah menggunakan komponen sebagai halaman penuh tanpa layout. Rutenya terdaftar, tetapi halaman gagal dengan error No hint path defined for [layouts]. karena Livewire mencari layout bawaan bernama layouts::app. Perbaikannya adalah menjalankan php artisan livewire:layout sekali, lalu menyesuaikan layout yang dihasilkan.
Kesalahan kedua adalah menempatkan koleksi besar pada properti publik, misalnya public $catatan; yang diisi seluruh isi tabel. Koleksi itu ikut diserialisasi ke snapshot dan dikirim bolak-balik pada setiap interaksi, sehingga payload membengkak tanpa manfaat. Properti publik cukup menyimpan kata kunci atau pengenal, sedangkan koleksi diambil dari database di dalam render().
Kesalahan ketiga adalah melupakan wire:key pada perulangan. Tanpa kunci, morphing mencocokkan butir berdasarkan posisi, sehingga daftar yang urutannya berubah dapat membuat isi DOM tertukar, misalnya nilai masukan yang sedang diisi pindah ke baris lain. Beri kunci berisi pengenal unik, seperti wire:key="catatan-{{ $note->id }}".
Ringkasan#
- Komponen Livewire adalah kelas PHP beserta template Blade yang dirender penuh oleh server pada muat awal, kemudian dibangun ulang oleh server untuk setiap interaksi yang dikirim livewire.js.
- Setiap interaksi mengirim snapshot berisi properti publik dan checksum ke endpoint pembaruan, lalu browser mengganti DOM secara selektif dengan HTML hasil render ulang di server.
- Hanya properti publik yang ikut snapshot, sehingga data besar sebaiknya diambil dari database di dalam
render()dan tidak disimpan sebagai properti. Livewire::test()danLivewire::mount()memungkinkan perilaku komponen diuji dan diperiksa langsung dari Tinker tanpa browser.
Referensi#
- Understanding Livewire — Livewire — Penjelasan resmi model kerja Livewire dari render awal hingga pembaruan halaman.
- Properties — Livewire — Aturan properti publik dan cara data komponen diserialisasi.
- Wire Model — Livewire
— Pemakaian
wire:modelbeserta modifier seperti.livedan.debounce.