Saltearse al contenido

Propiedades computadas

Las propiedades computadas son una forma de crear propiedades “derivadas” en Livewire. Al igual que los accesores en un modelo Eloquent, las propiedades computadas le permiten acceder a valores y almacenarlos en caché para un futuro acceso durante la solicitud.

Las propiedades computadas son particularmente útiles en combinación con las propiedades públicas de los componentes.

Uso básico

Para crear una propiedad computada, puede añadir el atributo #[Computed] sobre cualquier método de su componente Livewire. Una vez añadido el atributo al método, puede acceder a él como a cualquier otra propiedad.

Por ejemplo, aquí hay un componente ShowUser que utiliza una propiedad computada llamada user() para acceder a un modelo User Eloquent basado en una propiedad llamada $userId:

<?php
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Computed;
use Livewire\Component;
use App\Models\User;
class ShowUser extends Component
{
public $userId;
#[Computed]
public function user()
{
return User::find($this->userId);
}
public function follow()
{
Auth::user()->follow($this->user);
}
public function render()
{
return view('livewire.show-user');
}
}
<div>
<h1>{{ $this->user->name }}</h1>
<span>{{ $this->user->email }}</span>
<button wire:click="follow">Follow</button>
</div>

Dado que el atributo #[Computed] se ha añadido al método user(), el valor es accesible en otros métodos del componente y dentro de la plantilla Blade.

Ventaja de rendimiento

Quizá se pregunte: ¿por qué utilizar propiedades calculadas? ¿Por qué no llamar directamente al método?

Acceder a un método como una propiedad computada ofrece una ventaja de rendimiento sobre llamar a un método. Internamente, cuando una propiedad calculada se ejecuta por primera vez, Livewire almacena en caché el valor devuelto. De este modo, cualquier acceso posterior en la solicitud devolverá el valor almacenado en caché en lugar de ejecutarse varias veces.

Esto le permite acceder libremente a un valor derivado y no preocuparse por las implicaciones de rendimiento.

Romper la caché

Considere el siguiente escenario problemático:

  • Usted accede a una propiedad calculada que depende de cierta propiedad o estado de la base de datos
  • La propiedad subyacente o el estado de la base de datos cambia
  • El valor en caché de la propiedad se vuelve obsoleto y necesita ser recalculado

Para limpiar, o “reventar”, la caché almacenada, puede usar la función unset() de PHP.

Abajo hay un ejemplo de una acción llamada createPost() que, al crear una nueva entrada en la aplicación, hace que posts() se vuelva obsoleta - lo que significa que la propiedad posts() necesita ser recalculada para incluir la nueva entrada añadida:

<?php
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Computed;
use Livewire\Component;
class ShowPosts extends Component
{
public function createPost()
{
if ($this->posts->count() > 10) {
throw new \Exception('Maximum post count exceeded');
}
Auth::user()->posts()->create(...);
unset($this->posts);
}
#[Computed]
public function posts()
{
return Auth::user()->posts;
}
// ...
}

En el componente anterior, la propiedad calculada se almacena en caché antes de que se cree una nueva entrada porque el método createPost() accede a $this-&gt;posts antes de que se cree la nueva entrada. Para asegurar que $this->posts contiene los contenidos más actualizados cuando se accede dentro de la vista, la caché se invalida usando unset($this->posts).

Almacenamiento en caché entre peticiones

A veces se desea almacenar en caché el valor de una propiedad calculada durante toda la vida de un componente Livewire, en lugar de que se borre después de cada petición. En estos casos, puede utilizar las utilidades de caché de Laravel.

A continuación se muestra un ejemplo de una propiedad calculada llamada user(), donde en lugar de ejecutar la consulta Eloquent directamente, envolvemos la consulta en Cache::remember() para asegurar que cualquier solicitud futura la recupere de la caché de Laravel en lugar de volver a ejecutar la consulta:

<?php
use Illuminate\Support\Facades\Cache;
use Livewire\Attributes\Computed;
use Livewire\Component;
use App\Models\User;
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);
});
}
// ...
}

Como cada instancia única de un componente Livewire tiene un ID único, podemos usar $this-&gt;getId() para generar una clave de caché única que sólo se aplicará a futuras peticiones de esta misma instancia de componente.

Pero, como habrás notado, la mayor parte de este código es predecible y puede ser fácilmente abstraído. Debido a esto, el atributo #[Computed] de Livewire proporciona un útil parámetro persist. Aplicando #[Computed(persist: true)] a un método, puedes conseguir el mismo resultado sin ningún código extra:

use Livewire\Attributes\Computed;
use App\Models\User;
#[Computed(persist: true)]
public function user()
{
return User::find($this->userId);
}

En el ejemplo anterior, cuando $this-&gt;user es accedido desde su componente, continuará siendo cacheado mientras el componente Livewire esté en la página. Esto significa que la consulta Eloquent sólo se ejecutará una vez.

Livewire almacena en caché los valores persistentes durante 3600 segundos (una hora). Puede anular este valor predeterminado pasando un parámetro de seconds adicional al atributo #[Computed]:

Almacenamiento en caché en todos los componentes

En lugar de almacenar en caché el valor de una propiedad calculada durante el ciclo de vida de un único componente, puede almacenar en caché el valor de una propiedad calculada en todos los componentes de la aplicación utilizando el parámetro cache: true proporcionado por el atributo #[Computed]:

use Livewire\Attributes\Computed;
use App\Models\Post;
#[Computed(cache: true)]
public function posts()
{
return Post::all();
}

En el ejemplo anterior, hasta que la caché expire o se rompa, cada instancia de este componente en su aplicación compartirá el mismo valor de caché para $this-&gt;posts.

Si necesita borrar manualmente la caché de una propiedad calculada, puede establecer una clave de caché personalizada utilizando el parámetro key:

use Livewire\Attributes\Computed;
use App\Models\Post;
#[Computed(cache: true, key: 'homepage-posts')]
public function posts()
{
return Post::all();
}

¿Cuándo utilizar propiedades calculadas?

Además de ofrecer ventajas de rendimiento, hay algunos otros escenarios en los que las propiedades computadas son útiles.

Específicamente, al pasar datos a la plantilla Blade de su componente, hay algunas ocasiones en las que una propiedad computada es una mejor alternativa. A continuación se muestra un ejemplo del método render() de un componente simple que pasa una colección de posts a una plantilla Blade:

public function render()
{
return view('livewire.show-posts', [
'posts' => Post::all(),
]);
}
<div>
@foreach ($posts as $post)
<!-- ... -->
@endforeach
</div>

Aunque esto es suficiente para muchos casos de uso, aquí hay tres escenarios donde una propiedad computada sería una mejor alternativa:

Acceso condicional a valores

Si está accediendo condicionalmente a un valor cuya recuperación es costosa desde el punto de vista computacional en su plantilla Blade, puede reducir la sobrecarga de rendimiento utilizando una propiedad computada.

Considere la siguiente plantilla sin una propiedad computada:

<div>
@if (Auth::user()->can_see_posts)
@foreach ($posts as $post)
<!-- ... -->
@endforeach
@endif
</div>

Si un usuario tiene restringida la visualización de entradas, la consulta a la base de datos para recuperar las entradas ya se ha realizado, pero las entradas nunca se utilizan en la plantilla.

Aquí hay una versión del escenario anterior utilizando una propiedad computada en su lugar:

use Livewire\Attributes\Computed;
use App\Models\Post;
#[Computed]
public function posts()
{
return Post::all();
}
public function render()
{
return view('livewire.show-posts');
}
<div>
@if (Auth::user()->can_see_posts)
@foreach ($this->posts as $post)
<!-- ... -->
@endforeach
@endif
</div>

Ahora, como estamos proporcionando las entradas a la plantilla utilizando una propiedad computada, sólo ejecutamos la consulta a la base de datos cuando se necesitan los datos.

Usando plantillas en línea

Otro escenario en el que las propiedades computadas son útiles es usando plantillas en línea en tu componente.

A continuación se muestra un ejemplo de un componente en línea donde, debido a que estamos devolviendo una cadena de plantilla directamente dentro de render(), nunca tenemos la oportunidad de pasar datos a la vista:

<?php
use Livewire\Attributes\Computed;
use Livewire\Component;
use App\Models\Post;
class ShowPosts extends Component
{
#[Computed]
public function posts()
{
return Post::all();
}
public function render()
{
return <<<HTML
<div>
@foreach ($this->posts as $post)
<!-- ... -->
@endforeach
</div>
HTML;
}
}

En el ejemplo anterior, sin una propiedad computada, no tendríamos forma de pasar datos explícitamente a la plantilla Blade.

Omitiendo el método render

En Livewire, otra forma de reducir la burocracia en tus componentes es omitiendo completamente el método render(). Cuando se omite, Livewire utilizará su propio método render() devolviendo la vista Blade correspondiente por convención.

En este caso, obviamente no tienes un método render() desde el que puedas pasar datos a una vista Blade.

En lugar de reintroducir el método render() en su componente, puede proporcionar esos datos a la vista a través de propiedades computadas:

<?php
use Livewire\Attributes\Computed;
use Livewire\Component;
use App\Models\Post;
class ShowPosts extends Component
{
#[Computed]
public function posts()
{
return Post::all();
}
}
<div>
@foreach ($this->posts as $post)
<!-- ... -->
@endforeach
</div>