Creation, Listing and Reactivity 📜
Tags: tutorial, programming, laravel, beginners
Published: 2023-12-28 00:41:28

##Posts
To proceed with notifications, we need events that trigger them. We will notify a user whenever they are tagged in a post. So let's move on to creating the posts.

##New posts
Let's add an option to register posts to our navbar:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zaopjnel5to829ypmfvf.png)

In resources/views/livewire/layout/navigation.blade.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i34agte2m42szukk9qvw.png)
``` php
<x-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')" wire:navigate>
    {{ __('Posts') }}
</x-nav-link>
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0e6a4b91ys7625iscza.png)

``` php
<x-responsive-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')" wire:navigate>
    {{ __('Posts') }}
</x-responsive-nav-link>
```

Using Laravel commands we can create several resources at the same time.
For more details: [https://laravel.com/docs/10.x/eloquent#generating-model-classes](https://laravel.com/docs/10.x/eloquent#generating-model-classes)

In our case we will create the Model, migration and controller with resources:
`php artisan make:model -mrc Post`

In database/migrations/{date}_create_posts_table.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/su17p75j7kyfz5ta0gbc.png)

``` php
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->foreignId('tagged_user_id')->nullable()->constrained('users')->cascadeOnDelete();
            $table->string('message', 280);
            $table->timestamps();
        });
    }
```

tagged_user_id can be null, since a post can be created without having to tag someone.

Let's run the migrations:
`php artisan migrate`

In routes/web.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1bl59evnmaqmu7vmujh.png)

``` php
Route::view('posts','posts.index')->middleware('auth')->name('posts.index');
```

In app/Models/Post.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dsmzoot28p9td07vgbdu.png)

``` php
    protected $fillable = [
      'user_id',
      'tagged_user_id',
      'message',
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function taggedUser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'tagged_user_id');
    }
```


In app/Models/User.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jehekdi7szjvqgz91jx5.png)
``` php
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }

    public function taggedPosts(): HasMany
    {
        return $this->hasMany(Post::class, 'tagged_user_id');
    }
```

Let’s create the post registration and listing components:
`php artisan make:livewire posts.post-create`
`php artisan make:livewire posts.post-list`

Let's create the index.blade.php file in resources/views/posts, and import the default layout with our components:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9a2wpqqjijtmrmjs2kd.png)

``` php
<x-app-layout>
    @livewire('posts.post-create')
    @livewire('posts.post-list')
</x-app-layout>
```

**_One point of attention: To make the project simpler, we will not work with validation and repository layers._**

In resources/views/livewire/posts/post-create.blade.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kugipnja9f53v1kbjjjw.png)
``` php
<div>
    <form class="grid grid-cols-2 max-w-xl mx-auto m-6" wire:submit.prevent="save">
        <textarea
            wire:model="state.message"
            placeholder="{{ __('Post Message') }}"
            class="col-span-2 w-full shadow rounded-lg border-gray-200"
        ></textarea>
        @error('state.message') <span class="error">{{ $message }}</span> @enderror

        <select wire:model="state.tagged_user_id" class="mt-4 border-gray-200 rounded-lg">
            <option value=""></option>
            @foreach($users as $user)
                <option value="{{$user->id}}">{{$user->name}}</option>
            @endforeach
        </select>
        @error('state.tagged_user_id') <span class="error">{{ $message }}</span> @enderror

        <div class="flex justify-end">
            <button class="w-16 rounded-lg mt-4 bg-blue-500 shadow text-white">{{ __('Save') }}</button>
        </div>
    </form>
</div>

```

Let's add it to app/Livewire/Posts/PostCreate.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nuppw6prjl82due3j2d3.png)

``` php
    public $state = [
        'tagged_user_id' => null,
        'message' => ''
    ];

    public $users = null;

    public function mount()
    {
        $this->users = User::query()->get();
    }

    public function save(Request $request)
    {
        $this->validate([
            'state.message' => 'required|max:280',
            'state.tagged_user_id' => 'sometimes'
        ]);

        $request->user()->posts()->create($this->state);
        $this->reset('state');
    }
```

##List of posts
Now, we will proceed with the list of posts, where we will include both the posts we created and those in which we were tagged.

In resources/views/livewire/post/post-list.blade.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2ags5pc5tzvapycliwt.png)
``` php
<div>
    <div class="max-w-xl mx-auto mt-16">
        @foreach($posts as $post)
            <div class="bg-white p-6 rounded-md shadow-md text-center break-words mt-4">
                <p class="text-gray-700">
                    "{{$post->message}}"
                </p>
                <p class="text-blue-500 text-sm">{{ optional($post->taggedUser)->name ? '@'.$post->taggedUser->name : '' }}</p>
                <p class="text-end text-sm text-gray-500 mt-2">{{$post->user->name}}</p>
            </div>
        @endforeach
    </div>
</div>

```

In app/Livewire/Posts/PostList.php:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rn6gc296ixq85i23qbt5.png)
``` php
<?php

namespace App\Livewire\Posts;

use Livewire\Component;

class PostList extends Component
{
    public $posts;

    public function render()
    {
        $this->posts = auth()->user()->posts()
            ->orWhere('tagged_user_id', auth()->user()->id)
            ->orderBy('id', 'desc')
            ->get();

        return view('livewire.posts.post-list');
    }
}
```

##Reactivity
When a post is created, you need to reload the screen to view it. However, with Livewire, we were able to make the listing reactive. This means that when we create a post the list will be updated automatically.

But how?
Let's dispatch the creation component to the listing component, indicating that it is necessary to update the list.

In app/Livewire/Posts/PostCreate.php let's add dispatch:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydye8glxt1vabwdw9g5v.png)
``` php
        $this->dispatch('refreshPostList');
```

In app/Livewire/Posts/PostList.php let's add our listener with the refresh event:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fm0gf7l2ofter8qhdx6e.png)
``` php
    protected $listeners = [
        'refreshPostList' => '$refresh'
    ];
```

Ready! Our features are now reactive.