Instant response of the Like/Dislike buttons using Alpine.js in Livewire 3
I have logic for like/dislike button in two separate livewire components (LikeButton.php/DislikeButton.php)
The problem is I want like/dislike buttons react immediately after clicking
After clicking I need to wait and If my user will have slow internet he'll be waiting more way longer.
like-button.blade.php:
<div>
<button wire:click="toggleLike()">Like recipe</button>
{{ $recipe->countLikes() }}
</div>
dislike-button.blade.php:
<div>
<button wire:click="toggleDislike">Dislike recipe</button>
{{ $recipe->countDislikes() }}
</div>
LikeButton.php:
class LikeButton extends Component
{
public Recipe $recipe;
public function toggleLike()
{
// Check if user is authenticated
// if so, get the user
if (!$user = auth()->user()){
return $this->redirect(route('login-page'));
}
// Check if user has already liked recipe
// if true, then return unlike()
$hasLiked = $this->recipe->isLikedBy($user);
if ($hasLiked){
$this->recipe->unlikeBy($user);
}else{
$this->recipe->likeBy($user);
}
return $this->dispatch('refresh-dislikes');
}
#[On('refresh-likes')]
public function render()
{
return view('livewire.like-button');
}
}
DislikeButton.php:
class DislikeButton extends Component
{
public Recipe $recipe;
public function toggleDislike()
{
// Check if user is authenticated
// if so, get the user
if (!$user = auth()->user()){
return $this->redirect(route('login-page'));
}
// Check if user has already disliked recipe
// if true, then return undislike()
$hasDisliked = $this->recipe->isDislikedBy($user);
if ($hasDisliked){
$this->recipe->undislikeBy($user);
}else{
$this->recipe->dislikeBy($user);
}
return $this->dispatch('refresh-likes');
}
#[On('refresh-dislikes')]
public function render()
{
return view('livewire.dislike-button');
}
}
As you see, I am calling $this->dispatch('refresh-dislikes'); in LikeButton.php for rerender dislikes, and in DislikeButton.php I am calling $this->dispatch('refresh-likes'); for rerender likes.
Am I making a mistake when I am rerendering components in this way?
Is there any solution to achieve instant response using Alpine.js?
EDIT 01:
Currently I am using this Alpine.js logic:
<div
x-data="{
likeCount: @json($recipe->countLikes()),
isLiked: @json($recipe->isLikedBy(auth()->user())),
isGuest: @json(auth()->guest()),
toggleLike: function () {
if (this.isGuest){
window.location.href = '{{ route('login-page') }}';
return;
}
// decrement
if (this.isLiked) {
this.likeCount--;
this.isLiked = false;
} else {
// increment
this.likeCount++;
this.isLiked = true;
}
}
}"
class="flex items-center gap-1"
>
<button @click="toggleLike(); $wire.toggleLike()">
</button>
<span class="text-black" x-text="likeCount"></span>
</div>
It is working, but when I am clicking too fast or double click it starts to lag
Please or to participate in this conversation.