Livewire 3 was released with a few features using PHP Attributes on top of Component properties. In this lesson, let's look at them.
Livewire properties can be modified on both the frontend and backend. Sometimes this could be a security breach if someone tries to change the input value in their browser console. To prevent it, we can lock public properties.
To lock a public property, you must add a #[Locked]
attribute.
use Livewire\Attributes\Locked; class ShowPost extends Component{ #[Locked] public int $id; public function mount($postId): void { $this->id = $postId; } // ...}
If you try to modify the $id
property, Livewire will throw an Exception.
When using Model as a property, Livewire automatically will protect model's ID.
use App\Models\Post; class ViewPost extends Component{ public Post $post; public function mount(Post $post): void { $this->post = $post; } // ...}
Sometimes you might want to store component's properties in the URL. For example, when building a search or table filtering.
Let's return to a ShowPosts
Livewire component and add a simple search by title.
app/Livewire/ShowPosts.php:
class ShowPosts extends Component{ public string $search = ''; public function render(): View { return view('livewire.show-posts', [ 'posts' => Post::where('title', 'LIKE', '%' . $this->search. '%')->get(), ]); }}
resources/views/livewire/show-posts.blade.php:
<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 space-y-1 dark:text-gray-100"> <input type="text" wire:model.live="search" class="block mb-2 w-full border-gray-300 rounded-md shadow-sm"> @foreach($posts as $post) <h2 class="text-lg">{{ $post->title }}</h2> @endforeach </div> </div> </div></div>
Now to add ?search=
to the URL, we need to add a #[Url]
attribute to the search
property.
app/Livewire/ShowPosts.php:
use Livewire\Attributes\Url; class ShowPosts extends Component{ #[Url] public string $search = ''; public function render(): View { return view('livewire.show-posts', [ 'posts' => Post::where('title', 'LIKE', '%' . $this->search. '%')->get(), ]); }}
After writing ab
into a search input, the URL bar in the browser should show:
https://example.com/posts?search=ab
If you want to alias search
into, for example, q
, the #[Url]
attribute accepts parameter as
.
use Livewire\Attributes\Url; class ShowPosts extends Component{ #[Url(as: 'q')] public string $search = ''; public function render(): View { return view('livewire.show-posts', [ 'posts' => Post::where('title', 'LIKE', '%' . $this->search. '%')->get(), ]); }}
Now instead of ?search=ab
, you will see ?q=ab
.
By default, Livewire replaces the URL. This means that the browser's back button won't work. To make it work, you must set the history
parameter to true
.
use Livewire\Attributes\Url; class ShowPosts extends Component{ #[Url(history: true)] public string $search = ''; public function render(): View { return view('livewire.show-posts', [ 'posts' => Post::where('title', 'LIKE', '%' . $this->search. '%')->get(), ]); }}
Computed Properties are underrated and not used or used in the wrong place. Let's see how to define them and where they could be used.
To create a Computed Property, we must add the #[Computed]
attribute to the method in the Livewire component.
use Livewire\Attributes\Computed;use Illuminate\Support\Collection; class ShowComments extends Component{ public Post $post; public function mount(Post $post): void { $this->post = $post; } #[Computed] public function comments(): Collection { return $this->post->comments()->get(); } public function render(): View { return view('livewire.show-comments'); }}
We need to add the $this
object to access Computed Property. So in this example, in the Blade file, we would do $this->comments
.
<div class="space-y-1"> @foreach($this->comments as $comment) <p>{{ $comment->body }}</p> @endforeach</div>
When to use? One great usage of Computed Properties is to reduce queries. For example, if we want to show comments only for authenticated users, we would wrap foreach
with a @auth
directive.
<div class="space-y-1"> @auth @foreach($this->comments as $comment) <p>{{ $comment->body }}</p> @endforeach @endauth</div>
In this situation, when Computed Property is used, and the user can't view comments, the query isn't even made.
But when the user is authenticated, the comments are only fetched from the DB.