算出プロパティ
Computed properties は、Livewire で「派生した」プロパティを作成する方法です。Eloquent モデルのアクセサのように、Computed properties を使用すると、値にアクセスし、リクエスト中に後で使用するためにキャッシュできます。Computed properties are a way to create "derived" properties in Livewire. Like accessors on an Eloquent model, computed properties allow you to access values and cache them for future access during the request.
Computed properties は、コンポーネントの public property と組み合わせて使用すると特に便利です。Computed properties are particularly useful in combination with component's public properties.
基本的な使い方Basic usage
Computed property を作成するには、Livewire コンポーネント内の任意のメソッドの上に #[Computed]
属性を追加します。属性がメソッドに追加されると、他のプロパティと同様にアクセスできます。To create a computed property, you can add the #[Computed]
attribute above any method in your Livewire component. Once the attribute has been added to the method, you can access it like any other property.
Warning! 属性クラスをインポートしてください 必ず属性クラスをインポートしてください。たとえば、以下の
#[Computed]
属性には、次のインポートが必要です:use Livewire\Attributes\Computed;
。[!warning] Make sure you import attribute classes Make sure you import any attribute classes. For example, the below#[Computed]
attribute requires the following importuse Livewire\Attributes\Computed;
.
たとえば、以下は $userId
というプロパティに基づいて User
Eloquent モデルにアクセスするために、user()
という名前の computed property を使用する ShowUser
コンポーネントです。For example, here's a ShowUser
component that uses a computed property named user()
to access a User
Eloquent model based on a property named $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>
#[Computed]
属性が user()
メソッドに追加されているため、値はコンポーネント内の他のメソッドおよび Blade テンプレート内でアクセスできます。Because the #[Computed]
attribute has been added to the user()
method, the value is accessible in other methods in the component and within the Blade template.
Info: テンプレート内で
$this
を使用する必要があります 通常のプロパティとは異なり、computed properties はコンポーネントのテンプレート内で直接利用できません。代わりに、$this
オブジェクトでアクセスする必要があります。たとえば、posts()
という名前の computed property は、テンプレート内で$this->posts
を介してアクセスする必要があります。[!info] Must use$this
in your template Unlike normal properties, computed properties aren't directly available inside your component's template. Instead, you must access them on the$this
object. For example, a computed property namedposts()
must be accessed via$this->posts
inside your template.
Warning! Computed properties は
Livewire\Form
オブジェクトではサポートされていません。 Form(和訳) 内で Computed property を使用しようとすると、$form->property 構文を使用して blade でプロパティにアクセスしようとしたときにエラーが発生します。[!warning] Computed properties are not supported onLivewire\Form
objects. Trying to use a Computed property within a Form[https://livewire.laravel.com/docs/forms] will result in an error when you attempt to access the property in blade using $form->property syntax.
パフォーマンス上の利点Performance advantage
Computed properties を使用する理由は何でしょうか?メソッドを直接呼び出すのはなぜでしょうか?You may be asking yourself: why use computed properties at all? Why not just call the method directly?
メソッドを computed property としてアクセスすると、メソッドを呼び出すよりもパフォーマンス上の利点があります。内部的には、computed property が初めて実行されると、Livewire は返された値をキャッシュします。これにより、リクエスト内の後続のアクセスは、複数回実行する代わりに、キャッシュされた値を返します。Accessing a method as a computed property offers a performance advantage over calling a method. Internally, when a computed property is executed for the first time, Livewire caches the returned value. This way, any subsequent accesses in the request will return the cached value instead of executing multiple times.
これにより、派生した値に自由にアクセスでき、パフォーマンスへの影響を心配する必要がありません。This allows you to freely access a derived value and not worry about the performance implications.
[!warning] Computed properties are only cached for a single request It's a common misconception that Livewire caches computed properties for the entire lifespan of your Livewire component on a page. However, this isn't the case. Instead, Livewire only caches the result for the duration of a single component request. This means that if your computed property method contains an expensive database query, it will be executed every time your Livewire component performs an update.
Warning! Computed properties は、単一のリクエストに対してのみキャッシュされます Livewire が、computed properties をページ上の Livewire コンポーネントの有効期間全体にわたってキャッシュするという誤解がよくあります。ただし、これは当てはまりません。代わりに、Livewire は単一のコンポーネントリクエストの間だけ結果をキャッシュします。これは、computed property メソッドにコストのかかるデータベースクエリが含まれている場合、Livewire コンポーネントが更新を実行するたびに実行されることを意味します。
キャッシュの破棄Busting the cache
次の問題のあるシナリオを検討してください。Consider the following problematic scenario:
- 特定のプロパティまたはデータベースの状態に依存する computed property にアクセスするYou access a computed property that depends on a certain property or database state
- 基になるプロパティまたはデータベースの状態が変化するThe underlying property or database state changes
- プロパティのキャッシュされた値が古くなり、再計算する必要があるThe cached value for the property becomes stale and needs to be re-computed
格納されたキャッシュをクリアまたは「破棄」するには、PHP の unset()
関数を使用できます。To clear, or "bust", the stored cache, you can use PHP's unset()
function.
以下は、アプリケーションで新しい投稿を作成することにより、posts()
computed を古くする(つまり、新しく追加された投稿を含めるために computed property posts()
を再計算する必要がある)createPost()
というアクションの例です。Below is an example of an action called createPost()
that, by creating a new post in the application, makes the posts()
computed stale — meaning the computed property posts()
needs to be re-computed to include the newly added post:
<?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); // [tl! highlight]
}
#[Computed]
public function posts()
{
return Auth::user()->posts;
}
// ...
}
上記のコンポーネントでは、createPost()
メソッドが新しい投稿が作成される前に $this->posts
にアクセスするため、新しい投稿が作成される前に computed property がキャッシュされます。ビュー内でアクセスしたときに $this->posts
に最新のコンテンツが含まれるようにするために、キャッシュは unset($this->posts)
を使用して無効化されます。In the above component, the computed property is cached before a new post is created because the createPost()
method accesses $this->posts
before the new post is created. To ensure that $this->posts
contains the most up-to-date contents when accessed inside the view, the cache is invalidated using unset($this->posts)
.
リクエスト間のキャッシュCaching between requests
computed property の値を、リクエストごとにクリアするのではなく、Livewire コンポーネントの有効期間にわたってキャッシュしたい場合があります。このような場合は、Laravel のキャッシュユーティリティ を使用できます。Sometimes you would like to cache the value of a computed property for the lifespan of a Livewire component, rather than it being cleared after every request. In these cases, you can use Laravel's caching utilities[https://laravel.com/docs/cache#retrieve-store].
以下は、user()
という名前の computed property の例です。ここでは、Eloquent クエリを直接実行する代わりに、クエリを Cache::remember()
でラップして、今後のリクエストがクエリを再実行する代わりに Laravel のキャッシュから取得するようにします。Below is an example of a computed property named user()
, where instead of executing the Eloquent query directly, we wrap the query in Cache::remember()
to ensure that any future requests retrieve it from Laravel's cache instead of re-executing the query:
<?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);
});
}
// ...
}
Livewire コンポーネントの各ユニークなインスタンスにはユニークな ID があるため、$this->getId()
を使用して、この同じコンポーネントインスタンスの将来のリクエストにのみ適用されるユニークなキャッシュキーを生成できます。Because each unique instance of a Livewire component has a unique ID, we can use $this->getId()
to generate a unique cache key that will only be applied to future requests for this same component instance.
ただし、お気づきかもしれませんが、このコードのほとんどは予測可能であり、簡単に抽象化できます。このため、Livewire の #[Computed]
属性には、便利な persist
パラメータが用意されています。メソッドに #[Computed(persist: true)]
を適用すると、追加のコードなしで同じ結果を得ることができます。But, as you may have noticed, most of this code is predictable and can easily be abstracted. Because of this, Livewire's #[Computed]
attribute provides a helpful persist
parameter. By applying #[Computed(persist: true)]
to a method, you can achieve the same result without any extra code:
use Livewire\Attributes\Computed;
use App\Models\User;
#[Computed(persist: true)]
public function user()
{
return User::find($this->userId);
}
上記の例では、コンポーネントから $this->user
にアクセスすると、ページ上の Livewire コンポーネントの期間中、キャッシュされ続けます。これは、実際の Eloquent クエリが 1 回だけ実行されることを意味します。In the example above, when $this->user
is accessed from your component, it will continue to be cached for the duration of the Livewire component on the page. This means the actual Eloquent query will only be executed once.
Livewire は、永続化された値を 3600 秒(1 時間)キャッシュします。 #[Computed]
属性に追加の seconds
パラメータを渡すことで、このデフォルトをオーバーライドできます。Livewire caches persisted values for 3600 seconds (one hour). You can override this default by passing an additional seconds
parameter to the #[Computed]
attribute:
#[Computed(persist: true, seconds: 7200)]
Tip:
unset()
を呼び出すと、このキャッシュが破棄されます 前述したように、PHP のunset()
メソッドを使用して、computed property のキャッシュをクリアできます。これは、persist: true
パラメータを使用する computed properties にも当てはまります。キャッシュされた computed property でunset()
を呼び出すと、Livewire は computed property のキャッシュだけでなく、Laravel のキャッシュ内の基になるキャッシュされた値もクリアします。[!tip] Callingunset()
will bust this cache As previously discussed, you can clear a computed property's cache using PHP'sunset()
method. This also applies to computed properties using thepersist: true
parameter. When callingunset()
on a cached computed property, Livewire will clear not only the computed property cache, but also the underlying cached value in Laravel's cache.
すべてのコンポーネント間でキャッシュCaching across all components
単一のコンポーネントのライフサイクルの期間中 computed property の値をキャッシュする代わりに、#[Computed]
属性によって提供される cache: true
パラメータを使用して、アプリケーション内のすべてのコンポーネント間で computed の値をキャッシュできます。Instead of caching the value of a computed property for the duration of a single component's lifecycle, you can cache the value of a computed across all components in your application using the cache: true
parameter provided by the #[Computed]
attribute:
use Livewire\Attributes\Computed;
use App\Models\Post;
#[Computed(cache: true)]
public function posts()
{
return Post::all();
}
上記の例では、キャッシュが期限切れになるか破棄されるまで、アプリケーション内のこのコンポーネントのすべてのインスタンスが $this->posts
に対して同じキャッシュされた値を共有します。In the above example, until the cache expires or is busted, every instance of this component in your application will share the same cached value for $this->posts
.
computed property のキャッシュを手動でクリアする必要がある場合は、key
パラメータを使用してカスタムキャッシュキーを設定できます。If you need to manually clear the cache for a computed property, you may set a custom cache key using the key
parameter:
use Livewire\Attributes\Computed;
use App\Models\Post;
#[Computed(cache: true, key: 'homepage-posts')]
public function posts()
{
return Post::all();
}
Computed properties を使用するタイミングWhen to use computed properties?
パフォーマンス上の利点を提供するだけでなく、computed properties が役立つシナリオが他にもいくつかあります。In addition to offering performance advantages, there are a few other scenarios where computed properties are helpful.
具体的には、コンポーネントの Blade テンプレートにデータを渡す場合、computed property がより良い選択肢となる場合があります。以下は、シンプルなコンポーネントの render()
メソッドが posts
のコレクションを Blade テンプレートに渡す例です。Specifically, when passing data into your component's Blade template, there are a few occasions where a computed property is a better alternative. Below is an example of a simple component's render()
method passing a collection of posts
to a Blade template:
public function render()
{
return view('livewire.show-posts', [
'posts' => Post::all(),
]);
}
<div>
@foreach ($posts as $post)
<!-- ... -->
@endforeach
</div>
これは多くのユースケースに十分ですが、computed property がより良い選択肢となる 3 つのシナリオを次に示します。Although this is sufficient for many use cases, here are three scenarios where a computed property would be a better alternative:
条件付きで値にアクセスするConditionally accessing values
Blade テンプレートで取得するのに計算コストの高い値に条件付きでアクセスする場合、computed property を使用してパフォーマンスのオーバーヘッドを削減できます。If you are conditionally accessing a value that is computationally expensive to retrieve in your Blade template, you can reduce performance overhead using a computed property.
computed property がない次のテンプレートを検討してください。Consider the following template without a computed property:
<div>
@if (Auth::user()->can_see_posts)
@foreach ($posts as $post)
<!-- ... -->
@endforeach
@endif
</div>
ユーザーが投稿の表示を制限されている場合、投稿を取得するためのデータベースクエリは既に行われていますが、投稿はテンプレートで使用されません。If a user is restricted from viewing posts, the database query to retrieve the posts has already been made, yet the posts are never used in the template.
代わりに computed property を使用した上記のシナリオのバージョンを次に示します。Here's a version of the above scenario using a computed property instead:
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>
computed property を使用してテンプレートに投稿を提供しているため、データが必要な場合にのみデータベースクエリを実行します。Now, because we are providing the posts to the template using a computed property, we only execute the database query when the data is needed.
インラインテンプレートを使用するUsing inline templates
computed properties が役立つもう 1 つのシナリオは、コンポーネントでインラインテンプレートを使用することです。Another scenario when computed properties are helpful is using inline templates[/docs/components#inline-components] in your component.
以下はインラインコンポーネントの例です。ここでは、render()
内でテンプレート文字列を直接返しているため、ビューにデータを渡す機会がありません。Below is an example of an inline component where, because we are returning a template string directly inside render()
, we never have an opportunity to pass data into the view:
<?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;
}
}
上記の例では、算出プロパティがない場合、Bladeテンプレートに明示的にデータを渡す方法はありません。In the above example, without a computed property, we would have no way to explicitly pass data into the Blade template.
render メソッドの省略Omitting the render method
Livewireでは、コンポーネントのボイラープレートを削減する別の方法として、render()
メソッドを完全に省略することが挙げられます。省略した場合、Livewireは独自のrender()
メソッドを使用して、対応するBladeビューを慣例により返します。In Livewire, another way to cut down on boilerplate in your components is by omitting the render()
method entirely. When omitted, Livewire will use its own render()
method returning the corresponding Blade view by convention.
この場合、Bladeビューにデータを渡せる render()
メソッドは明らかに存在しません。In these case, you obviously don't have a render()
method from which you can pass data into a Blade view.
コンポーネントに render()
メソッドを再導入する代わりに、算出プロパティを使用してビューにそのデータを提供できます。Rather than re-introducing the render()
method into your component, you can instead provide that data to the view via computed properties:
<?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>