# Skill: Livewire 3 — Referência para Claude Code ## Versão usada Livewire **3.x** (via `livewire/livewire: ^3`) ## Padrões deste projeto ### Componentes — em `app/Livewire/[Modulo]/` ``` app/Livewire/ ├── Dashboard/PerformanceDashboard.php ├── Hardware/HardwareManager.php ├── Hardware/HardwareForm.php ├── Catalog/HardwareCatalog.php ├── Bottleneck/BottleneckCalculator.php ├── Compare/ComponentComparer.php └── Upgrade/UpgradeSuggestions.php ``` Views em `resources/views/livewire/[modulo]/[nome].blade.php`. ### Propriedades e validação com atributos PHP 8 ```php use Livewire\Attributes\Validate; class HardwareForm extends Component { #[Validate('required|in:cpu,gpu,ram,storage')] public string $type = 'cpu'; #[Validate('required|min:2|max:150')] public string $name = ''; } ``` ### Paginação com trait ```php use Livewire\WithPagination; class HardwareManager extends Component { use WithPagination; // Sempre chamar resetPage() ao mudar filtros public function updatedSearch(): void { $this->resetPage(); } } ``` ### Debounce em inputs de busca ```html ``` ### Eventos Livewire → Alpine (via bridge) ```php // No componente Livewire $this->dispatch('open-panel', id: $this->editingId); $this->dispatch('close-panel'); $this->dispatch('component-saved'); ``` ```javascript // public/js/app.js converte para CustomEvent // Alpine escuta com @event.window ``` ```html
``` **Todo novo evento Livewire→Alpine precisa ser registrado em `public/js/app.js`.** ### Listeners de eventos entre componentes ```php protected $listeners = ['component-saved' => 'handleComponentSaved']; public function handleComponentSaved(): void { $this->dispatch('close-panel'); session()->flash('success', 'Salvo!'); $this->resetPage(); } ``` ### wire:key em loops — obrigatório ```html @foreach($components as $item)
@endforeach ``` ### Loading states ```html ``` ## Armadilhas Comuns - **Esquecer `resetPage()` ao mudar filtros** → paginação mostra página vazia - **Não registrar evento em `app.js`** → Alpine não recebe o evento Livewire - **`wire:model` sem opção default em select** → valor inicial null causa erro de validação falso - **`x-if` vs `x-show` no painel** → usar `x-if="panelOpen"` para recriar o Livewire ao reabrir (evita form com dados stale) - **`wire:key` ausente em loops paginados** → re-render quebra a identidade dos elementos - **Mudar propriedade em `updatedX()` que dispara outro `updatedX()`** → loop infinito ## Exemplos de Código Correto ```php // render() sempre retorna view com dados public function render(): View { return view('livewire.hardware.hardware-manager', [ 'components' => UserComponent::where('user_id', auth()->id()) ->with('catalog') ->paginate(10), ]); } // Dispatch com payload $this->dispatch('open-panel', id: $this->editingId); // Dispatch sem payload $this->dispatch('component-saved'); ``` ```html
@if(!empty($catalogResults))
@foreach($catalogResults as $r) @endforeach
@endif
``` ## O Que NUNCA Fazer - Nunca usar Alpine para fazer requisições ao servidor — isso é responsabilidade do Livewire - Nunca usar `$this->emit()` (Livewire 2) — usar `$this->dispatch()` (Livewire 3) - Nunca esquecer `wire:key` em loops com paginação - Nunca chamar `Auth::attempt()` dentro de um Livewire component — lógica de auth está nas rotas - Nunca misturar estado de UI (aberto/fechado de modal) com estado de dados do servidor — UI fica no Alpine