Optymalizacja jest kluczowa przy budowaniu aplikacji, szczególnie kiedy liczba użytkowników rośnie i rosną także wymagania dotyczące wydajności. W kontekście Livewire możemy wprowadzić różne usprawnienia, które pozwalają zredukować liczbę żądań AJAX, odciążyć bazę danych lub przyspieszyć działanie interfejsu. W dzisiejszym artykule przyjrzymy się, jak zastosować takie techniki, od usprawnienia komunikacji pomiędzy front-endem i backendem, przez caching, aż po metody debugowania.
Artykuł jest kontynuacją naszych wcześniejszych materiałów:
Optymalizacja liczby wywołań AJAX
Livewire komunikuje się z backendem poprzez serię żądań AJAX, automatycznie wykonywanych przy zmianach stanu komponentu. Jeśli jednak mamy wiele pól powiązanych z wire:model, może to generować zbyt wiele zapytań. Poniżej prezentujemy trzy modyfikatory, które pomogą zmniejszyć tę liczbę:
wire:model.lazy
Zamiast reagować na każdą zmianę w polu (każde wpisywanie znaku), wire:model.lazy wysyła żądanie dopiero po „wyjściu” z pola (np. po zmianie fokusu). Oznacza to, że jeśli użytkownik wypełnia pole tekstowe, Livewire poczeka, aż zakończy on edycję, zanim odświeży stan komponentu.
wire:model.defer
wire:model.defer zbiera zmiany w polu i wysyła je dopiero, gdy użytkownik wykona jakąś akcję, która wymusza synchronizację z backendem – na przykład, gdy kliknie przycisk z wire:click lub zatwierdzi formularz z wire:submit.
W powyższym przykładzie zmiany w polu tekstowym nie będą wysyłane natychmiast, lecz dopiero po kliknięciu przycisku „Szukaj”.
wire:model.debounce
Debounce w Livewire pozwala wprowadzić opóźnienie przed wysłaniem żądania AJAX. Przykładowo, wire:model.debounce.500ms zbiera wpisywane znaki i wyśle aktualizację dopiero, gdy użytkownik przestanie pisać przez minimum 500 ms.
Ta opcja jest bardzo przydatna przy tworzeniu pól wyszukiwania w locie, by nie przeciążać bazy danych ciągłymi żądaniami podczas wpisywania.
Zmniejszanie liczby odświeżeń akcji (np. wire:click.prevent)
Często zdarza się, że niektóre akcje w Livewire mogą powodować odświeżanie lub zachowania typowe dla elementów HTML. Dla przykładu, jeśli mamy przycisk w formularzu, standardowo kliknięcie może wysłać żądanie HTTP, co w kontekście Livewire może być niepożądane. W takich sytuacjach warto użyć modyfikatora .prevent:
Dzięki temu unikniemy domyślnej akcji kliknięcia (odświeżania strony), zachowując tylko wywołanie metody saveTask.
Integracja cachingu w Livewire
Wydajność bazy danych jest kluczowa w większości aplikacji. Jednym ze sposobów na odciążenie serwera jest cache’owanie wyników zapytań. W Laravelu możemy wykorzystać do tego Cache facade lub cache() helper.
W komponentach Livewire stosujemy podejście analogiczne do reszty Laravelowej aplikacji. Przykład poniżej pokazuje cache’owanie wyników skomplikowanego zapytania na 60 sekund:
use Illuminate\Support\Facades\Cache;
// ...
public function getTasks()
{
return Cache::remember('tasks_list', 60, function () {
// Tu może być bardziej złożone zapytanie
return Task::orderBy('created_at', 'desc')->get();
});
}
Jeśli często wykonujemy to samo zapytanie, a dane nie zmieniają się co sekundę, taki mechanizm pozwala znacząco przyspieszyć działanie aplikacji.
Uwaga: Pamiętaj, żeby w razie aktualizacji bazy (np. dodania nowego zadania) wyczyścić lub odświeżyć cache, np. poprzez
Cache::forget('tasks_list').
Debugowanie w Livewire
Livewire Devtools
Livewire Devtools to rozszerzenie do przeglądarek (obecnie działa w Chrome, Brave, Firefox), które pozwala podejrzeć stan komponentów, listę zarejestrowanych eventów, a nawet modelowane właściwości w czasie rzeczywistym. Aby z niego skorzystać, należy:
- Zainstalować rozszerzenie Livewire Devtools w przeglądarce.
- Upewnić się, że w aplikacji jest zainstalowany pakiet
livewire/livewire. - Otworzyć narzędzia deweloperskie w przeglądarce i przejść do zakładki „Livewire”.
Debugbar i inne narzędzia
Aby debugować zapytania do bazy danych, można posłużyć się np. pakietem Laravel Debugbar. Pozwala on podejrzeć wszystkie wykonywane zapytania, co jest szczególnie ważne, kiedy chcemy zidentyfikować obszary, w których aplikacja może być przeciążona.
Inną metodą jest oczywiście klasyczne logowanie (\Log::info($dane)) wewnątrz metod Livewire i przeglądanie logów w pliku storage/logs/laravel.log.
Ćwiczenia
Poniżej przedstawiam dwa proste ćwiczenia, które pomogą Ci w praktyczny sposób opanować omówione zagadnienia.
Ćwiczenie 1. Dodanie wyszukiwania z mechanizmem debounce
Załóżmy, że w naszej aplikacji mamy komponent TaskList, który wyświetla listę zadań. W tym ćwiczeniu dodamy pole wyszukiwania, tak aby użytkownik mógł filtrować zadania po nazwie.
Krok 1: Dodaj właściwość w komponencie
public $searchQuery = '';
Krok 2: Zastosuj wire:model.debounce
W widoku Blade, gdzie chcemy umożliwić wyszukiwanie:
@foreach($tasks as $task)
- {{ $task->name }}
@endforeach
Krok 3: Modyfikacja metody pobierającej zadania
public function getTasksQuery()
{
// Jeśli użytkownik wpisał coś do wyszukiwania – filtrujemy
$query = Task::query();
if (!empty($this->searchQuery)) {
$query->where('name', 'LIKE', '%' . $this->searchQuery . '%');
}
return $query->orderBy('created_at', 'desc');
}
public function render()
{
// Tutaj używamy metody getTasksQuery()
$tasks = $this->getTasksQuery()->paginate(10);
return view('livewire.task-list', compact('tasks'));
}
Dzięki debounce, żądanie do Livewire pójdzie dopiero po 500 ms nieaktywności użytkownika podczas wpisywania. W efekcie nie będziemy „spamować” serwera zapytaniami co ułamek sekundy.
Ćwiczenie 2: Cache zapytania
Załóżmy, że nasza lista zadań pobiera dane z bazy, a chcemy ograniczyć liczbę zapytań. Możemy cache’ować wyniki na pewien czas (np. 60 sekund).
Krok 1: Dodaj logikę cache w metodzie pobierającej zadania
use Illuminate\Support\Facades\Cache;
public function getTasksQuery()
{
return Cache::remember('tasks.list.' . $this->searchQuery, 60, function () {
$query = Task::query();
if (!empty($this->searchQuery)) {
$query->where('name', 'LIKE', '%' . $this->searchQuery . '%');
}
return $query->orderBy('created_at', 'desc');
});
}
Tutaj klucz cache uwzględnia zmienną searchQuery – jeśli się różni, to cache będzie inny (zapewnia to osobny wynik dla różnych filtrów wyszukiwania).
Krok 2: Odświeżanie cache przy zmianach w bazie
Kiedy dodajemy nowe zadanie, powinniśmy odświeżyć cache. Możemy to zrobić w komponencie odpowiedzialnym za dodawanie lub edycję zadań:
public function createTask()
{
$this->validate();
Task::create([
'name' => $this->name,
'status' => $this->status,
]);
// Czyszczenie cache przy dodaniu nowego zadania
Cache::forget('tasks.list.' . $this->searchQuery);
$this->emit('zadanieUtworzone');
}
Dodatkowo, jeśli mamy wiele wariantów kluczy (np. różne searchQuery), możemy rozważyć zapisywanie danych w osobnym kluczu (np. Cache::forget('tasks.list.*') z użyciem wildcard) bądź w bazie innego mechanizmu do szerszego czyszczenia cache.
Podsumowanie
Livewire domyślnie zapewnia wysoki komfort pracy, jednak w przypadku bardziej złożonych aplikacji warto wprowadzać dodatkowe optymalizacje:
- Zmniejszenie liczby wywołań AJAX – użycie modyfikatorów
lazy,defer,debounce, a także świadome posługiwanie sięwire:click.prevent. - Caching – w prosty sposób integrujemy się z Laravel Cache, co pozwala odciążyć bazę danych.
- Debugowanie – korzystanie z Livewire Devtools i Laravel Debugbar, które pomagają nam w wyłapaniu wąskich gardeł i błędów.
Dzięki tym praktykom Twoja aplikacja napisania w Laravel + Livewire może być jeszcze bardziej responsywna, niezawodna i skalowalna. To znacznie poprawi doświadczenie użytkowników końcowych i ułatwi dalszy rozwój projektu.