📕

Livewire入門

2024/04/04に公開

はじめに

Laravelを使ったプロジェクトに参画することが多いのですが、最近フロントエンドでVueを使った開発が増えています。しかし、Vueを学習するコストは高く、周りのエンジニアでもなかなか苦労している方も見かけます。新しい技術を学ぶことはかなりの労力と時間がかかるし、知識不足のため予想外の挙動に時間を取られたりということも少なくありません。
そんなところに、最近livewireというlaravelの知識がそのまま使えて、かつViewをVueのようにコンポーネントに分けて管理しやすくするようなライブラリを見つけたので共有したいと思います。

Livewireとは

vue、reactなどで実現できる動的なViewの生成をJavaScriptを使わず、PHPのコードのみで実現できるライブラリ。
通信はAjaxを利用するが、livewireが勝手にやってくれるので、vueで作る時のようにaxiosライブラリを使ってAPIをコールしたりといったコードを書く必要はない。

メリット

1. 動的で管理のしやすいUIを構築することができる。

JqueryのようにDOM操作をする必要がない
bladeをcomponent化することができるため管理が簡単になる

2. Laravelの構文をそのまま使えるのでキャッチアップが簡単

クリックアクションなどのイベント発火時のロジックをPHPで(
laravelのController)で記述することができるので、phperにとってはかなりコーディングが楽になる

デメリット

1. laravelでしか使えない

laravel-livewireという名前がついているのでわかる通りlaravelのライブラリになるので他のPHPフレームワークでは使うことができません。

2. SPAなど複雑なUIは作成できない

Laravelのbladeを使用することが前提になるため、SPAを作るためにフロントエンドとバックエンドを分けた構成をとった時は使えません。

Livewire vs Vue.js

作るアプリケーションの要件によって変わってくるところで、どちらが絶対にいいというものはありません。ネット上でもLivewireを使うか、Vue.jsを使うかは議論になっているようです。
個人的には以下のような観点があるかなと思います。

アプリケーションの構成

シングルページアプリケーションなど複雑なフロントエンドの場合 → Vue.js
サーバーサイドレンダリングのアプリケーションの場合 → Livewire

チームメンバーの知見

チームメンバーがLaravelに精通しているということであればLivewireを選択するのは非常に良い選択肢になると思います。Vueを学習するのとLaravelwireを学習するのでは学習コストが段違いです。

開発スピード

開発スピードについて考慮するのであれば、これもLivewireが良いと思います。
vueを使う場合それなりのbaseとなる処理を作成する必要がありますが、livewireの場合はartisanコマンド一つでコンポーネントを作成することができるため、非常に楽です。

ユーザビリティ

ユーザビリティを考えてリッチなUIにしたい場合は、どれくらいの規模になるかによりますが、Vueを使った方がいい場合があるかもしれません。前述したSPA構成まで実現するにはVue.jsを使わないとそもそもlivewireでは実現不可能です。
(livewireを使うとユーザビリティが下がるということではありません。)

思い浮かんだことだけ書いたので、実際使ってみると想定と違うなどあるかもしれませんが基本的にLaravelでSSRアプリケーションを作る場合livewireは非常に有力なライブラリなのかなという所感でした。

使い方

実際どのようにbladeのコンポーネント化が行われるのかモーダルを作成してみていくことにします。
詳しくは公式ドキュメントを参照ください。
https://laravel-livewire.com/docs/2.x/quickstart

今回のモーダルのコンポーネントを作成することから始めましょう。

$ php artisan make:livewire counter-sample

↑のコマンドで
Http/Controllers/livewire/CounterSample.php
resources/views/livewire/counter-sample.blade.php
配下に今回のコンポーネントファイルが生成されます。

CounterSample.php
<?php

namespace App\Livewire;

use Livewire\Component;

class counterSample extends Component
{
    public function render()
    {
        return view('livewire.counter-sample');
    }
}
counter-sample.blade.php
<div>
    {{-- The best athlete wants his opponent at his best. --}}
</div>

次にコンポーネントを組み込むことになる親のViewを作成しましょう

index.blade.php
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
    <link rel="stylesheet" href="{{ asset('/css/app.css') }}">
    @livewireStyles
  </head>
  <body>
    <div class="container">
        <h1>カウントアップ</h1>
    </div>
    @livewireScripts
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
  </body>
</html>

livewireを使うにはまず、<head>タグと<body>タグの中に@livewireStylesというアノテーションを追記します。

今回は以下のような画面を作りました。ボタンとカウントはlivewireコンポーネントとして切り出すことにします。

次にControllerの方でボタンを押された時のロジックを書いていきます。

CounterSample.php
<?php

namespace App\Livewire;

use Livewire\Component;

class CounterSample extends Component
{
    public $count = 0;
 
    public function increment()
    {
        $this->count++;
    }
    
    public function render()
    {
        return view('livewire.counter-sample');
    }
}

$countでボタンを押された時のカウントを保持するステートを宣言できます。
またロジックはfunctionとして定義することで簡単にアクションを定義することができます。

Controllerで定義したステートとイベントロジックを使ってコンポーネントを作っていきます。
先ほど生成したcounter-sample.blade.phpに記載していきます。

counter-sample.blade.php
<div>
    <div style="text-align: center">
        <button type="button" class="btn btn-primary"
                style="--bs-btn-padding-y: .80rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .75rem;"
                wire:click="increment"
                >
            Count Up
        </button>
        <h1>{{ $count }}</h1>
    </div>
</div>

wire:clickによってボタンをクリックした時に、さっき定義したincrementメソッドがコールされるようになります。
また、ステートは今までのbladeの同様に{{ $count }}のように記載することで参照することができます。

最後にこのコンポーネントを親のViewに渡して画面を作ります。

index.blade.php
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
    <link rel="stylesheet" href="{{ asset('/css/app.css') }}">
    @livewireStyles
  </head>
  <body>
    <div class="container">
        <h1>カウントアップ</h1>
        <livewire:counter-sample /> 
    </div>
    @livewireScripts
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
  </body>
</html>

<livewire:counter-sample>でコンポーネントを埋め込んだことになります。

このように簡単にコンポーネントを作成することが可能で、ロジックやステートについてもコントローラにまとめられているため、非常に使いやすいです。

まとめ

ユーザビリティの高まりもあり、UIをモダンなデザインにすることがアプリの人気を大きく分けるような時代だと思います。その中で開発速度を落とすことなく、かつ今までの知見を活かした開発を実現するにはLivewireを選択肢に入れてもいいのではないかと思いました。

Discussion