Livewireの普通の使い方とVoltの比較
====
## バージョン
- Laravel 10.x
- Livewire 3.2.6 https://github.com/livewire/livewire
- Volt 1.6.0 https://github.com/livewire/volt
最近でも機能が追加されてるので2023年12月時点の情報。
## ドキュメント
https://livewire.laravel.com/docs/volt
## 3つのスタイル
一つのLaravelプロジェクト内で3つのスタイルを同時に使える。簡単なページはVolt functional、複雑なページは普通などで使い分けしてもいい。最初はVolt functionalで作ったけど複雑になってきたので普通の使い方に作り変えるなんてこともよく発生する。
### Livewire スタンダード
PHPファイルとBladeファイルが分かれた普通の使い方。
実装例:JetstreamのLivewireスタック。
Voltの前に普通の使い方の理解は必須。
この記事は普通の使い方でのこの機能はVoltでどう書くのかって情報のまとめ。
### Volt functional
BladeファイルだけでLivewireを使う新しい方法。Vue.js風の表現ならシングルファイルLivewireコンポーネント。
実装例:Breezeのlivewire-functionalスタック。 https://github.com/laravel/breeze/tree/1.x/stubs/livewire-functional/resources/views/livewire
```php
0]);
$increment = fn () => $this->count++;
?>
{{ $count }}
```
Laravel Folioと似てるし一緒に発表されたけどFolioとは関係ない。
### Volt Class-based
Voltを普通の使い方に近い無名classを使うスタイルにしたもの。
実装例:Breezeのlivewireスタック。 https://github.com/laravel/breeze/tree/1.x/stubs/livewire/resources/views/livewire
```php
count++;
}
} ?>
{{ $count }}
```
複雑化しただけでこれの追加は余計だった気がする。Laravelは複数の使い方ができるのが混乱の元なのに余計な選択肢を増やすのは明らかに悪い。
## コンポーネント作成コマンド
### Livewire スタンダード
```
php artisan make:livewire counter
```
### Volt functional
```
php artisan make:volt counter
```
ファイル一つなので2回目からはコマンドを使うより既存のコンポーネントを複製して書き換えが現実的な使い方。
### Volt Class-based
functionalと同じ。
## ファイルの場所
### Livewire スタンダード
- `app/Livewire/`にPHPファイル
- `resources/views/livewire`にBladeファイル
### Volt functional
`resources/views/livewire`にBladeファイルのみ。
`resources/views/pages`に置いたBladeファイルも使える。Folio用に作ったページだけど機能を追加したくなってVoltに変更、みたいな使い方を想定しているのだろう。FolioのファイルベースルーティングとVoltを同時に使えるかは試してないので不明。
### Volt Class-based
functionalと同じ。
## プロパティとmount
### Livewire スタンダード
```php
posts = Post::all();
}
}
```
### Volt functional
```php
posts = Post::all();
});
?>
```
### Volt Class-based
```php
posts = Post::all();
}
}
?>
```
## アクション
### Livewire スタンダード
```php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Post;
class CreatePost extends Component
{
public $title = '';
public $content = '';
public function save()
{
Post::create([
'title' => $this->title,
'content' => $this->content,
]);
return redirect()->to('/posts');
}
}
```
```php
```
### Volt functional
```php
$this->title,
'content' => $this->content,
]);
return redirect()->to('/posts');
};
?>
```
### Volt Class-based
スタンダードとほぼ同じなので以降は省略。
## バリデーション
### Livewire スタンダード
`Validate`アトリビュートで指定。
```php
use Livewire\Attributes\Validate;
use Livewire\Component;
use App\Models\Post;
class CreatePost extends Component
{
#[Validate('required|min:3')]
public $title = '';
#[Validate('required|min:3')]
public $content = '';
}
```
### Volt functional
`rules()`で指定。
```php
'required|min:6', 'email' => 'required|email']);
$submit = function () {
$this->validate();
// ...
};
?>
```
## Computed プロパティ
### Livewire スタンダード
```php
use Livewire\Attributes\Computed;
use Livewire\Component;
use App\Models\User;
class ShowUser extends Component
{
#[Computed]
public function count()
{
return User::count();
}
```
### Volt functional
```php
{{ $this->count }}
```
## ページネーション
### Livewire スタンダード
`WithPagination`の追加を忘れやすい。
```php
Post::paginate(10),
]);
}
}
```
### Volt functional
```php
['posts' => Post::paginate(10)]);
?>
@foreach ($posts as $post)
//
@endforeach
{{ $posts->links() }}
```
## ファイルアップロード
### Livewire スタンダード
```php
photo->store('photos');
}
}
```
### Volt functional
```php
use function Livewire\Volt\{state, usesFileUploads};
usesFileUploads();
state(['photo']);
$save = function () {
$this->validate([
'photo' => 'image|max:1024',
]);
$this->photo->store('photos');
};
```
## Full-page component レイアウト指定
### Livewire スタンダード
render()かclassにLayoutアトリビュートで指定。レイアウトは基本的に固定なのでアトリビュートでの指定でいいだろう。
```php
{{ $title ?? config('app.name') }}
```
### Livewire スタンダード
```php
title($this->post->title);
}
}
```
ちなみにLivewire3のドキュメントからは消えてるけどtitle以外のデータをレイアウトに渡す`layoutData()`もある。
```php
public function render()
{
return view('livewire.post-show')
->layoutData(['foo' => 'bar']);
}
```
`Title`アトリビュートで指定する方法もあるけど固定のtitleでしか使えないので使うことはほとんどない。
```php
use Livewire\Attributes\Title;
use Livewire\Component;
class CreatePost extends Component
{
// ...
#[Title('Create Post')]
public function render()
{
return view('livewire.create-post');
}
}
```
### Volt functional
```php
use function Livewire\Volt\{state, title};
state('post');
title(fn() => $this->post->title);
```
固定のtitleなら`titie('Post');`も可能だけどこれもほとんど使わないだろう。
### Volt Class-based
ここだけ特殊で`rendering()`で指定。
```php
title('Create Post');
// ...
}
// ...
```
## Full-page component ルーティング
### Livewire スタンダード
PHPファイルを指定。
```php
use App\Livewire\CreatePost;
Route::get('/posts/create', CreatePost::class)->name('post.create');
```
### Volt functional
Bladeファイルを指定。`Volt::route()`の戻り値はRouteなので通常通りnameの指定なども可能。
```php
use Livewire\Volt\Volt;
Volt::route('/users', 'user-index')->name('user.index');
```
## URLクエリパラメータ
### Livewire スタンダード
```php
url();
```
## イベントリスナー
### Livewire スタンダード
```php
use Livewire\Component;
use Livewire\Attributes\On;
class Dashboard extends Component
{
#[On('post-created')]
public function updatePostList($title)
{
// ...
}
}
```
### Volt functional
```php
use function Livewire\Volt\{on};
on(['post-created' => function () {
//
}]);
```
## 以上
よく使うだろう機能はまとめたのでこれ以上はドキュメントを参照。
アドベントカレンダー用の記事。
https://qiita.com/advent-calendar/2023/laravel
ここは長文を想定してないけど最近は外部に書いてないのでここに書く。
ドメインを破棄した時用にGitHubにも残している。
https://github.com/puklipo/articles/blob/main/livewire-volt.md