Symfony版Livewireこと、Live Componentさん

[Symfony Advent Calendar 2021の](https://qiita.com/advent-calendar/2021/symfony)記事です。
今回はSymfony UXの新機能、Live Componentについて書きます。

## Symfony UXとは
なるべくサーバサイドのことに注力できるように、フロントエンドのUXに関するJavaScriptとサーバサイドをうまいこと繋ぎ込んでくれるライブラリ群です。
composerでサーバサイド側のプログラムとnpmパッケージをダウンロードして利用します。
2021年12月現在、以下が用意されています。

| name | 内容 |
|---|---|
| UX Chart.js | Chart.jsがいい感じにつかえるやつ |
| UX Cropper.js | Cropper.jsがいい感じにつかえるやつ |
| UX Dropzone | ドラッグ＆ドロップでファイルアップロードできるようにしてくれるやつ |
| UX LazyImage | 画像遅延読み込みをいい感じにしてくれるやつ |
| UX Swup | [Swup](https://swup.js.org/)がいい感じにつかえるやつ |
| UX Turbo | [Hotwire Turbo](https://turbo.hotwired.dev/)がいい感じにつかえるやつ |
| Twig Component | 【実験段階】 再利用可能なTwigコンポーネントがつくれるやつ |
| **Live Component** | 【実験段階】 **Ajaxで再描画できるTwigコンポーネントがつくれるやつ** |

## Live Componentを使ってみる。。前に

[Live Component](https://github.com/symfony/ux-live-component)は、Livewire、Phoenix LiveViewにインスパイアされて作成されたようです。上記で書いた通り、**Twig Componentの一種**です。まずはTwig Componentについて知る必要があります。

### Twig Componentについて
[Twig Component](https://github.com/symfony/ux-twig-component)は、コンポーネントクラスとTwigテンプレートのセットで、他のテンプレート上から呼び出すことができます。イメージ的には[Embed Controller](https://symfony.com/doc/current/templates.html#embedding-controllers)に似ています。Live Componentもですが、実験段階なライブラリになります。

Twig Componentはいたってシンプルに作ることができます。まずはコンポーネントクラス。

```php:src/Compoenents/HelloComponent.php
namespace App\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent('hello')]
class HelloComponent
{
    public string $name = '';

    public function getGreet(): string
    {
        return sprintf('こんにちは、%sさん', $this->name);
    }
}
```

アトリビュートで、`#[AsTwigComponent('hello')]`をつけることで、`hello`という名前のコンポーネントとして利用することができます。
`name`を使って`getGreet()`で挨拶を返します。今回は使っていませんが、**当然オートワイヤリング可能です。**続いてコンポーネントで使うテンプレート。

```twig:templates/components/hello.html.twig
<div class="greet">
{{ this.greet }}
</div>
```

コンポーネントクラスのGetterメソッドには`this.***`という形でアクセスできます。ここでは`this.greet`で`getGreet()`にアクセスしています。
最後に、コンポーネントを使う側のテンプレートです。

```twig:templates/index.html.twig
<div>
<h3>あいさつ</h3>
{{ component('hello', {name: 'ほげほげ'}) }}
</div>
```
`{{ component('コンポーネント名`, 引数) }}`でコンポーネントを呼び出すことができます。引数を設定するとパブリックなプロパティに値を代入してくれます。

上記の結果は、

```html
<div>
<h3>あいさつ</h3>
<div class="greet">
こんにちは。ほげほげさん
</div>
</div>
```

となります。べんりー。


## Live Componentを使ってみる。

さて、本題のLive Componentです。Live Componentでは、すこし記述がかわります。まずはクラス。

```diff_php:src/Compoenents/HelloComponent.php
namespace App\Components;

use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
+ use Symfony\UX\LiveComponent\DefaultActionTrait;

- #[AsTwigComponent('hello')]
+ #[AsLiveComponent('hello')]
class HelloComponent
{
+    use DefaultActionTrait;
+
+   #[LiveProp(writable: true)]
    public string $name = '';

    public function getGreet(): string
    {
        return sprintf('こんにちは、%sさん', $this->name);
    }
}
```

アトリビュートが`#[AsTwigComponent('hello')]`から`#[AsLiveComponent('hello')]`に変更しました。Live Componentへはこれだけで変更されます。
続いて`use DefaultActionTrait;`の追加ですが、再描画行う際にクラス内の`__invoke()`を実行するようになっているので、何もしない`__invoke()`メソッドを追加します。なお、Live Componentは実質Controllerとのこと。
最後にプロパティの$nameに`#[LiveProp(writable: true)]`を追加します。`LiveProp`は該当のプロパティをステートフルプロパティに変更します。オプションの`writable: true`をつけることで、上書き可能なプロパティになります。

続いてテンプレート。

```diff_twig:templates/components/hello.html.twig
- <div class="greet">
+ <div class="greet" {{ init_live_component(this) }}>
+     <input type="text" name="name" value="{{ this.name }}" data-action="live#update">
{{ this.greet }}
</div>
```

divタグに`{{ init_live_component(this) }}`が追加されました。これはライブコンポーネントの初期化が行われます。Symfony UXは[Stimulus](https://stimulus.hotwired.dev/)を使用しており、Stimulusの初期化の記述をこれで追加します。

また、名前が変えれるように入力フォームを用意し、`data-action="live#update"`を追加しています。テキストボックスにdata-actionを追加すると、入力内容が変わるごとに`live#update`が実行され、Ajax経由で`HelloComponent::__invoke()`の実行結果を取得して、再描画を行います。

呼び出す側は修正の必要がありません。

では実行してみましょう。


https://twitter.com/ippey_s/status/1473622761419702272


このような感じで、入力したテキストがすぐに反映されています。
今回のサンプルは単純なものでしたが、DBのデータを扱ったり認可・認証をからめたコンポーネントも作れるようです。
例えば、

https://twitter.com/ippey_s/status/1472479958350311425


こんなのとか。
実験段階なので、まだまだ改修が入りそうですが、ページ再読み込みストレスをかなり軽減してくれる機能となっていて、Symfony UXの中でも今後がとても楽しみな機能です。ぜひ一度お試しください。