Livewire Like/Dislike Component for Social Networks: Step-by-Step

In this tutorial, we will use Livewire to create a component for Like/Dislike, similar to YouTube or any social network. We will show the count of likes and dislikes, also minimizing the number of queries to the DB.

finished livewire component


Laravel Project Preparation

We'll show the list of posts and the number of votes for every post.

For this demo, we'll use our own Laravel Breeze Pages Skeleton which will give use Breeze-like layout but with a public page for posts list.

First, we need a Post Model, Controller, and View. For now, without any Livewire.

php artisan make:model Post -mc

database/migrations/xxxx_create_posts_table.php:

return new class extends Migration {
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('text');
$table->timestamps();
});
}
};

app/Models/Post.php:

class Post extends Model
{
protected $fillable = [
'title',
'text',
];
}

app/Http/Controllers/PostController.php:

class PostController extends Controller
{
public function __invoke(): View
{
$posts = Post::latest()->paginate();
 
return view('posts', compact('posts'));
}
}

And a simple Blade file to show the list of the posts.

resources/views/posts.blade.php:

<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
{{ __('Posts') }}
</h2>
</x-slot>
 
<div class="py-12">
<div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
<div class="overflow-hidden bg-white shadow-sm dark:bg-gray-800 sm:rounded-lg">
<div class="p-6 text-gray-900 dark:text-gray-100">
@foreach($posts as $post)
<h3 class="text-xl font-medium">{{ $post->title }}</h3>
<p>{{ $post->text }}</p>
<hr class="my-4">
@endforeach
 
{{ $posts->links() }}
</div>
</div>
</div>
</div>
</x-app-layout>

list of posts

Next, we need to save votes. For this, we will create a Vote Model.

php artisan make:model Vote -m

database/migrations/xxxx_create_votes_table.php:

return new class extends Migration {
public function up(): void
{
Schema::create('votes', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->smallInteger('vote');
$table->timestamps();
});
}
};

app/Models/Vote.php:

class Vote extends Model
{
protected $fillable = [
'post_id',
'user_id',
'vote',
];
}

Now let's add Vote relations to the Post Model.

app/Models/Post.php:

use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasMany;
 
class Post extends Model
{
protected $fillable = [
'title',
'text',
];
 
public function votes(): HasMany
{
return $this->hasMany(Vote::class);
}
 
public function userVotes(): HasOne
{
return $this->votes()->one()->where('user_id', auth()->id());
}
}

We'll need two relations. The first one is just a regular One To Many relation which we will use to create and update the vote for the post.

The second one is more interesting: the userVotes relation will return null if a user hasn't voted yet. Otherwise, it will return the Vote model from which we will be able to tell if a user liked or disliked a post.


Livewire Component

Now let's create a Livewire component.

php artisan make:livewire LikeDislike

First, let's add the Livewire component after the post text and...

The full tutorial [15 mins, 2867 words] is only for Premium Members

Login Or Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1056 lessons, total 42 h 44 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials