Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Навіщо wire:key у циклах Livewire і що ламається без нього?

Після кожного запиту Livewire не замінює HTML компонента повністю, а морфить DOM: порівнює старе й нове дерево елемент за елементом і змінює лише відмінності. Так зберігаються фокус, введений текст, стан Alpine.

Проблема зі списками. Без підказок морфінг зіставляє елементи за позицією. Видалили перший елемент списку - і алгоритм вирішує, що змінився вміст кожного елемента, а останній зник:

@foreach ($todos as $todo)
    <li>
        <input type="checkbox" wire:model="done.{{ $todo->id }}">
        <span x-data="{ editing: false }">{{ $todo->title }}</span>
    </li>
@endforeach

Наслідки: стан Alpine (editing), фокус і введення «переїжджають» на сусідні рядки, анімації спрацьовують не там, а вкладені Livewire-компоненти отримують чужі дані.

wire:key дає кожному елементу стабільний ідентифікатор - морфінг зіставляє елементи за ключем:

@foreach ($todos as $todo)
    <li wire:key="todo-{{ $todo->id }}">...</li>
@endforeach

@foreach ($posts as $post)
    <livewire:post-card :$post :wire:key="$post->id" />
@endforeach

Правила:

  • ключ - ідентифікатор даних (id), а не індекс циклу. $loop->index не допомагає: після видалення елемента індекси зсуваються так само;
  • ключ має бути унікальним у межах компонента. Якщо на сторінці два списки з тих самих моделей, додайте префікс: "comment-{{ $id }}", "reply-{{ $id }}";
  • для вкладених Livewire-компонентів у циклі ключ обов'язковий - без нього стан дочірніх компонентів змішується.

Налаштування smart_wire_keys (у Livewire 4 увімкнено за замовчуванням) допомагає з ключами глибоко вкладених компонентів, але не звільняє від wire:key у циклах.

Ще один випадок - залежні поля: <select> міст, що змінюється разом з обраною областю, потребує wire:key="{{ $regionId }}", щоб значення коректно скинулося.

Альтернатива морфінгу для складних випадків - wire:replace: замінити вміст елемента повністю замість порівняння.

Докладніше в документації: Морфінг

Схожі питання