Data about properties in Laravel Livewire
Content Index
- Locked Properties
- Resetting Properties
- Supported Property Types
- Personal Opinion
- Conclusion
- Deferring Updates for wire:model
- .debounce: Modifies the update time
- .lazy: Sends updates on blur
- .defer: Disable updates
- $refresh Property in Laravel Livewire Components
- Component components in Livewire are complex
- Introduction to the "Refresh" Property
- Alternatives and Communication Between Components
- Computed Properties in Laravel Livewire
- Advantages of Computed Properties
In this post, we'll look at key data about properties, the ones we use in our form-type components in Laravel Livewire.
Locked Properties
Below is a ShowPost component that stores the ID of a Post model as a public property called $id. To prevent a curious or malicious user from modifying this property, you can add the #[Locked] attribute to the property:
use Livewire\Attributes\Locked;
use Livewire\Component;
class ShowPost extends Component
{
#[Locked]
public $id;
public function mount($postId)
{
$this->id = $postId;
}
// ...
}By adding the #[Locked] attribute, you ensure that the $id property will never be altered.
Another way would be by declaring the property as private:
private $id;By default, any public property exposed in a component can be manipulated from the view. Even a malicious user can:
- Open the developer tools.
- Duplicate a field that has wire:model.
- Change the field name to another property of the class.
- Modify its value and send that payload to the backend.
This means a user could try to modify, for example, an id, a role_id, or any sensitive property.
Resetting Properties
We can also reset properties using the $this->reset() method:
class ManageTodos extends Component
{
public $todo = '';
public function addTodo()
{
$this->reset('todo');
}
}Supported Property Types
The official documentation clarifies that the supported types are those that can be easily converted to JSON, because Livewire communicates through serialized payloads.
class TodoList extends Component
{
public $todos = []; // Array
public $todo = ''; // String
public $maxTodos = 10; // Integer
public $showTodos = false; // Boolean
public $todoFilter; // Null
}Personal Opinion
Although it's curious (or even a bit crude, as I say) that a user can manipulate wire:model from the console, the reality is that it's part of the framework's reactive nature.
So if you handle properties that:
- shouldn't be changed,
- contain IDs,
- represent permissions,
- expose protected data,
then #[Locked] is mandatory.
Conclusion
These features —reset(), valid property types, and locking with #[Locked]— complete the view of how Livewire handles its internal properties and how we must protect them when they are sensitive.
Deferring Updates for wire:model
A critical aspect you need to consider when working with wire:model is that, by default, when detecting changes, Livewire sends messages to the server every few milliseconds to maintain synchronization between what exists on the client with the server and vice versa.
The problem with these requests is that, if the default configuration is used, too many requests are sent to the server, and if we have multiple clients connected at the same time sending these types of requests, it can cause performance problems and even server errors because each request causes the server to need more and more resources that may not be available due to the high demand for resources.
Fortunately, this no longer happens in modern versions of Livewire from version 3 onwards, therefore, the options we have here DO NOT apply or cannot be used for the new versions of Laravel and are explained for purely informational purposes.
If we look at the documentation, we will see that:
- lazy no longer appears for wire:model.
- defer doesn't work as before either.
- debounce does exist, but with a different syntax and a much more coherent behavior.
This is important because the old documentation explains things that no longer apply, and in the modern version the framework's philosophy changed quite a bit.
To avoid these problems, we have to define extra features on our wire:model that can be of three types; for these examples, you can use any of the form fields that currently exist for posts or categories; for example:
resources/views/livewire/dashboard/post/save.blade.php
***
<div class="col-span-6 sm:col-span-4">
<x-label for="">Title</x-label>
<x-input-error for="title" />
<x-input class="block w-full" type="text" wire:model="title" />
</div>
***.debounce: Modifies the update time
This setting modifies the update time of the wire:model field; by default it is 150 milliseconds; for example, to modify this time to 500ms:
<x-input class="block w-full" type="text" wire:model.debounce.500ms="title" />This feature can be used if you are using the live option which allows updating the property associated with wire:model every time we type, resulting in:
<x-input type="text" wire:model.live.debounce.500ms='title' class="w-full" />.lazy: Sends updates on blur
This setting disables the synchronization of the wire:model field and only updates the state when the field loses focus (on blur).
<x-input class="block w-full" type="text" wire:model.lazy="title" />.defer: Disable updates
This setting completely disables the synchronization of the wire:model field; therefore, changes made to that field will be sent when a message is sent to the server provided by any other update process in the application.
<x-input class="block w-full" type="text" wire:model.deboun="title" />$refresh Property in Laravel Livewire Components
One of the complications I see with Livewire, that is, a negative point if we compare it with Inertia or directly with Laravel or the implementation itself, is that I sometimes consider it very abstract and there are many ways to do the same thing.
The Problem of Consistency in Interaction
What do I mean by this? For example, in this case, we have a simple problem. We have a detail component and the Cart component included within the detail component:
ShowComponent.php
@if ($post->type == 'advert')
<div class="mycard mb-5 ms-auto block max-w-96">
<div class="mycard-body">
@livewire('shop.cart')
</div>
</div>
@empty(session('cart')[$post->id])
{{-- si el item esta en el carrito, removemos la opcion de agregar --}}
<div class="mycard-primary mb-5 block max-w-96">
<div class="mycard-body">
<h3 class="text-center text-3xl mb-4">Add this item</h3>
@livewire('shop.cart', ['post' => $post, 'type' => 'add'])
</div>
</div>
@endempty
@endifThe problem is that, when we interact with the shopping cart, we want to reload the Detail component, since there are other related components. But, we don't have a direct way.
Component components in Livewire are complex
The solution, unfortunately, is not that simple, and it's what I say can be a bit abstract, everything that has to do with components here in Livewire. Since, well, there could be many ways to do the same thing, and it may not be so clear what we have to do: whether to reload the entire page with JavaScript, whether to do it using Alpine, which also has some ways, whether to communicate the component in some way, whether to use keys to redraw the component, or directly the property I'm going to talk about.
What I mean is that there are many ways to do the same thing, and it's quite abstract and complicated to really know what we have to do, which is a bit of what I want to talk about in the next two classes. Since, again, this is a somewhat trivial thing we want to do, but to get there, really, at least for me, it takes a little effort.
Introduction to the "Refresh" Property
So, what do I want to talk about regarding refresh? Having clarified that a little, since what we want to achieve is to reload that component. So, for this, notice that we have a property that they don't reference very well either, called refresh. In this example, it's being used from a button, for example:
@endempty <button type="button" wire:click="$refresh">Refresh Demo</button> @endifSo, now we will see that it reloads the entire main page, including the cart components, which is what we want.
Alternatives and Communication Between Components
In this example, we are not communicating the components, but directly reloading this one. Another way, which would be a little more efficient, would be to redraw this using a key, which I think we'll see something about. I say it would be a little more efficient because, obviously, when we are reloading, we are making a request to the server once again and it is not going to reload or refresh only this part of the components, but also what this matrix component is. But in this case, we really don't care much because it's a post, but well, as I say, all of this is quite abstract.
The problem is that in both cases the component and the components are siblings, so, and everything is in the show, and we have and they are independent, but even so, that action does not happen directly in the show, but directly in the child component.
Maybe with Alpine we could do something, but that's a bit of what was commented on at the beginning, the logic becomes quite complicated simply to do that reload. So, in these cases, just like I did before when I was reloading here (which I don't know what, now it appeared because this doesn't appear in red, I'll check later), when we are doing the "piracy" here that I told you about that we wanted to put this in red, sometimes I prefer to do those types of implementations that are not working for me for some reason. I don't know what happened, I'll see now, instead of going around in circles here trying to figure out how it could be done, so to speak, the correct way, which would be inserting the pin, as they say, in the most efficient way. So, before getting to that, I prefer to reload the entire component.
Computed Properties in Laravel Livewire
An interesting feature in Livewire is the use of computed properties. These are simply functions defined in the component with the structure get<PropertyName>Property, and are consumed simply by accessing <propertyName>. The main particularity of these properties is that they are useful for deriving values from the database or other persistent storage, such as a cache.
app/Http/Livewire/Dashboard/Category/Index.php
public function getCategoryProperty()
{
if ($this->categoryToDelete)
return Category::find($this->categoryToDelete->id);
return "Sin categoría seleccionada";
}To consume this property from the class or the view, you must always use $this:
$this->categoryYou can display the value in the view in the following way:
resources/views/livewire/dashboard/category/index.blade.php
"No category selected"
You can also declare a computed property using the #[Computed] attribute, as shown below:
// function getCategoryProperty()
#[Computed()]
function category() {
***
}Let's implement a computed property that returns the current time and compare it with a traditional method to better understand its behavior:
#[Computed()]
function getTimeP()
{
sleep(1);
return time();
}
function getTime()
{
sleep(1);
return time();
}And in the view:
{{ $this->getTimeP }}
{{ $this->getTimeP }}
{{ $this->getTimeP }}
{{ $this->getTimeP }}
{{ $this->getTimeP }}
<br>
{{$this->getTime()}}
{{$this->getTime()}}When computed properties are used, the value is automatically cached. Therefore, you will see that, no matter how many times it is invoked, getTimeP will return the same value, for example:
1728727286 1728727286 1728727286 1728727286 1728727286
Instead, the traditional method getTime() will be executed every time, so you will get:
1728727287 1728727288
This demonstrates that computed properties cache the result until one of the internal properties that affect their result changes, or it is explicitly updated.
Advantages of Computed Properties
Method with custom logic: You can build a property that internally performs complex operations, such as database queries or derived calculations.
Automatic caching: Once the value is calculated, it is saved internally. The method is not executed again unless a change in its dependencies is detected or it is explicitly updated.
This is ideal for costly operations or when you want to avoid repeated calls to external services or the database.
class ShowUser extends Component
{
public $userId;
#[Computed]
public function user()
{
$key = 'user'.$this->getId();
$seconds = 3600; // 1 hour...
return Cache::remember($key, $seconds, function () {
return User::find($this->userId);
});
}
// ...
}
class ShowUser extends Component
{
public $userId;
#[Computed]
public function user()
{
return User::find($this->userId);
}
}
<h1>{{ $this->user->name }}</h1>The next step is to learn how to create a list, a complete Datatable with sorting in Laravel Livewire.
I agree to receive announcements of interest about this Blog.
We will learn about other features of properties, types of supported properties, property reset, locked properties, computed properties, and the refresh property.