Menyusun komponen di dalam komponen: nesting dengan passing parameter, wire:key untuk list bersarang, serta membangun komponen reusable seperti button, badge, dan form field dengan slots dan props agar UI konsisten.

Aplikasi yang sehat tersusun dari komponen kecil yang bisa dipakai ulang, bukan satu komponen raksasa. Di episode 8 kita sudah memecah layout; sekarang kita masuk lebih dalam: nesting (komponen di dalam komponen) dan reusable components (komponen yang dipakai di banyak tempat dengan konfigurasi berbeda).
Kedua hal ini menentukan kualitas kode jangka panjang. Tombol, badge, dan field form yang konsisten di seluruh aplikasi bukan hanya soal estetika — mereka membuat perubahan styling dan perilaku menjadi satu titik perubahan, bukan ratusan edit manual.
Sebuah komponen Livewire bisa merender komponen Livewire lain — dan state-nya terisolasi (kecuali dihubungkan lewat props/events, episode 7):
<div>
<livewire:posts-table :status="$activeStatus" />
<livewire:posts-stats />
</div>PostsTable menerima status sebagai prop, PostsStats mandiri dan berkomunikasi lewat event (post-created, episode 7). Masing-masing punya snapshot sendiri — perubahan di satu komponen tidak otomatis merender ulang yang lain, kecuali memang dihubungkan.
| Aspek | Satu komponen besar | Nesting |
|---|---|---|
| Ukuran payload | Semua state jadi satu snapshot | Snapshot terpisah per komponen |
| Kecepatan morphing | Setiap aksi me-render seluruh halaman | Hanya komponen yang berubah |
| Perawatan | Sulit dipahami, sulit diuji | Tiap komponen kecil, fokus |
| Reuse | Tidak mungkin | Komponen bisa dipakai di halaman lain |
Ada trade-off: setiap komponen nested menambah request internal saat ia pertama dimuat. Jangan pecah tanpa alasan — pecah saat komponen punya tanggaung jawab berbeda atau butuh di-reuse.
Parameter diteruskan lewat atribut tag, dan bisa berupa scalar, array, atau model:
<livewire:user-avatar :user="$post->author" size="sm" />public function mount(User $user, string $size = 'md')
{
$this->user = $user;
$this->size = $size;
}Aturan penting: parameter hanya diterima di mount(). Jika nilai berubah di parent setelah mount, child tidak otomatis ikut — kecuali dengan #[Reactive] (episode 7) atau event.
Saat merender list komponen, setiap item butuh wire:key pada elemen loop yang dibungkus komponen:
@foreach ($posts as $post)
<livewire:post-card :post="$post" :key="'post-card-'.$post->id" />
@endforeachTanpa wire:key, Livewire tidak bisa melacak elemen mana yang ditambah/dihapus — gejala klasiknya: input di komponen kehilangan fokus atau menampilkan state yang salah saat list berubah. Ini kasus yang sama dengan episode 5, tapi berlaku untuk komponen dalam loop.
Komponen presentasional (badge, button, form field) biasanya tidak butuh state server — cukup komponen Blade biasa dengan props dan slots:
@props(['variant' => 'gray'])
<span {{ $attributes->merge(['class' => "badge badge-{$variant}"]) }}>
{{ $slot }}
</span><x-badge variant="green">Published</x-badge>
<x-badge variant="yellow">Draft</x-badge>Perhatikan {{ $attributes }} — attribute yang diteruskan saat pemakaian (seperti class tambahan) otomatis digabungkan. Ini membuat komponen Blade fleksibel tanpa menjadi kaku.
Field form dengan label, error, dan binding yang konsisten:
@props(['label', 'name'])
<div>
<label for="{{ $name }}">{{ $label }}</label>
<input
id="{{ $name }}"
name="{{ $name }}"
wire:model="{{ $name }}"
{{ $attributes }}
>
@error($name)
<span class="text-red-600">{{ $message }}</span>
@enderror
</div><x-form-field label="Judul" name="title" />
<x-form-field label="Isi" name="body" type="textarea" />Satu komponen field = konsistensi styling + error handling di seluruh aplikasi. Perubahan tampilan cukup di satu tempat.
Tip
Aturan pemilihan yang perlu diingat: butuh state/logika server → komponen Livewire; hanya tampilan + props → komponen Blade. Jangan membuat komponen Livewire untuk badge atau button sederhana — itu menambah snapshot dan request tanpa manfaat. Simpan Livewire untuk komponen yang benar-benar interaktif.
| Kebutuhan | Jenis komponen |
|---|---|
| Badge, button, icon | Blade component (props + slots) |
| Form field dengan error | Blade component + wire:model |
| Tabel data dengan pagination | Livewire component |
| Widget statistik yang auto-refresh | Livewire component |
| Form kompleks dengan validasi | Livewire + Form Object |
Aturan praktisnya sederhana: semakin banyak interaksi dan state, semakin pantas jadi Livewire.
wire:key pada list komponen: gejala kehilangan fokus/state salah — tambahkan :key di tag komponen.mount() tidak ikut — gunakan #[Reactive] atau event.$attributes: komponen menjadi kaku, tidak bisa menerima class/attribute tambahan.Inti yang harus dibawa pulang:
mount(); perubahan setelahnya perlu #[Reactive] atau event.wire:key wajib pada list komponen dalam loop.Di episode 18 selanjutnya kita akan membahas JavaScript & third-party integration — $this->js() untuk mengeksekusi script dari server, $wire.$entangle untuk state bersama, serta integrasi chart dan editor seperti tiptap/ckeditor tanpa framework JS. Sampai jumpa di episode 18!