Kurnia Andi Nugroho
0 comment
Kalau kamu pengguna Livewire, satu hal yang pasti: Livewire 4 bukan sekadar update biasa. Ini adalah rilis paling besar sepanjang sejarah Livewire.
Tapi tenang…Ini bukan tentang nambah kerumitan, justru kebalikannya:
default yang lebih masuk akal friction makin kecil dan tools yang lebih kuat buat bikin UI modern tanpa ribet
Tim Livewire benar-benar rethink ulang: “Gimana sih seharusnya komponen Livewire itu terasa saat dipakai sehari-hari?”
Dan jujur saja… hasilnya keren.
Mari kita bahas satu per satu, pelan-pelan.
Perubahan paling kelihatan di Livewire 4 adalah cara nulis komponen.
Di Livewire 3, kita biasa bolak-balik:
Sekarang? Semua bisa dalam satu file Blade.
<?php // resources/views/components/⚡counter.blade.php
use Livewire\Component;
new class extends Component {
public $count = 0;
public function increment()
{
$this->count++;
}
};
?>
<div>
<h1>{{ $count }}</h1>
<button wire:click="increment">+</button>
</div>
<style>
/* CSS khusus komponen ini */
</style>
<script>
/* JavaScript khusus komponen ini */
</script>
Kenapa ini penting?
Dan ya… ikon ⚡ itu memang sengaja. Biar sekali lihat di file tree, kamu langsung tahu:
“Oh ini Livewire, bukan Blade biasa.”
Kalau kamu tim “rapi-rapi enterprise”, tenang…
Untuk komponen besar, Livewire 4 tetap mendukung format terpisah tapi dalam satu folder:
⚡counter/
├── counter.php
├── counter.blade.php
├── counter.css (opsional)
├── counter.js (opsional)
└── counter.test.php (opsional)
Bikin pakai:
php artisan make:livewire Counter --mfc
Dan yang keren: bisa convert bolak-balik kapan saja**.
php artisan livewire:convert
Sekarang Livewire ngenalin:
Route::livewire('/posts/create', 'pages::post.create');
Dibanding versi lama:
Route::get('/posts/create', CreatePost::class);
Kenapa ini lebih enak?**
Livewire 4 datang dengan opini struktur (dan ini bagus).
Default:
pages:: → halamanlayouts:: → layoutRoute::livewire('/dashboard', 'pages::dashboard');
Kalau aplikasimu modular, kamu bisa bikin sendiri:
admin::billing::reports::Ini bikin codebase lebih kebaca dan scalable.
Sekarang kamu bisa langsung nulis CSS & JS di komponen:
<div>
<h1 class="title">{{ $count }}</h1>
<button wire:click="$js.celebrate">+</button>
</div>
<style>
.title {
color: blue;
font-size: 2rem;
}
</style>
<script>
this.$js.celebrate = () => {
confetti()
}
</script>
Keunggulan besar:
this (alias $wire).css & .js → auto cachedKalau mau global:
<style global>
Ini game changer.
Dengan @island, kamu bisa bikin bagian kecil yang update sendiri tanpa nge-refresh seluruh komponen.
@island
<div>
Revenue: {{ $this->revenue }}
<button wire:click="$refresh">Refresh</button>
</div>
@endisland
Yang di luar island nggak ikut render ulang.
Dulu?
Sekarang? Satu directive, selesai.
Dan bukan cuma DOM…Query database juga ikut terisolasi.
Slots sekarang reactive:
<livewire:card :$post>
<h2>{{ $post->title }}</h2>
<button wire:click="delete({{ $post->id }})">Delete</button>
</livewire:card>
Method delete() tetap dipanggil di parent.
Attribute forwarding juga makin natural:
<livewire:post.show :$post class="mt-4" />
<div {{ $attributes }}>
...
</div>
Livewire 4 sekarang punya sorting bawaan:
<ul wire:sort="reorder">
@foreach ($items as $item)
<li wire:sort:item="{{ $item->id }}">
{{ $item->title }}
</li>
@endforeach
</ul>
public function reorder($item, $position)
{
// $item = ID
// $position = index baru
}
✔️ Animasi halus ✔️ Bisa multi-list ✔️ Bisa drag handle
<div wire:transition>
Alert message
</div>
Untuk wizard:
#[Transition(type: 'forward')]
public function next() {}
#[Transition(type: 'backward')]
public function previous() {}
Ini pakai native browser API, jadi super smooth.
Beberapa directive favorit:
wire:show → toggle tanpa requestwire:text → update teks instanwire:bind → bind atribut HTML$dirty → deteksi perubahan<div wire:show="$dirty">
Ada perubahan yang belum disimpan
</div>
Setiap request otomatis punya atribut data-loading.
<button wire:click="save" class="data-loading:opacity-50">
Save
</button>
CSS-first, simpel, bersih.
@placeholder
<div class="animate-pulse h-32 bg-gray-200"></div>
@endplaceholder
Nggak perlu view terpisah. Skeleton tinggal di tempatnya.
wire:ref$refs#[Json] method$js actionContoh interceptor global:
Livewire.interceptRequest(({ onError }) => {
onError(({ response, preventDefault }) => {
if (response.status === 419) {
preventDefault()
alert('Session habis')
location.reload()
}
})
})
Tenang. Livewire 4 backward compatible.
Install:
composer require livewire/livewire:^4.0
Livewire 4 bukan cuma “versi baru”.
Kurnia Andi Nugroho
Web & Mobile App Developer, Laravel, Inertia, Vue.Js, React.Js
Founder of Lagikoding.com Laravel Enthusiast & Web Developer