Livewireを使ってLaravelプロジェクトをインタラクティブにしよう

今日は、Laravelアプリケーションにインタラクティブな要素を簡単に追加する方法、その名もLivewireについてお話ししようと思います。Ajaxを書かずにリアルタイムのインタラクティブなインターフェイスを実現するLivewireは、まさに魔法のようなフレームワークです。さあ、その魔法を見てみましょう!

目次

Livewireとは?

Livewireは、Laravel用のフルスタックフレームワークで、サーバー側のレンダリングパワーとフロントエンドのリアクティビティを組み合わせます。これにより、複雑なJavaScriptを書かずに、動的なUIを簡単に構築できます。

STEP

Livewireのコンセプト

Livewireは、Laravelアプリケーションを豊かにするために開発された、画期的なフレームワークです。一言で言えば、Livewireはサーバーサイドのレンダリングの力を活用し、JavaScriptのようなクライアントサイドスクリプト言語に頼ることなく、ダイナミックなユーザーインターフェイスを実現します。

STEP

サーバーサイドレンダリングのパワー

従来のウェブアプリケーションでは、動的なインタラクションを実現するために、多量のJavaScriptが必要でした。これには、データのフェッチ、DOMの操作、ユーザーイベントのハンドリングなどが含まれます。しかし、LivewireはLaravelの強力なサーバーサイドレンダリングを活用して、これらのプロセスをサーバー側で処理します。

LivewireコンポーネントはPHPクラスとBladeビューで構成されており、サーバーサイドでの変更がリアルタイムでビューに反映されるようになっています。これは、サーバーからビューへのデータの受け渡しを簡単にし、フロントエンドの複雑さを大幅に削減します。

STEP

リアクティビティの秘密

Livewireの魔法は、サーバーとのリアルタイムの通信にあります。ユーザーがインターフェイス上でアクションを起こすたびに、例えばボタンをクリックするたびに、Livewireはそのアクションを検知し、適切なサーバーサイドのPHPメソッドを呼び出します。そして、その結果を元にビューを更新し、ユーザーに即座に反映させます。

このプロセスは、AjaxリクエストやWebSocket通信のような技術を裏で使用していますが、開発者はこれらの複雑なフロントエンドの詳細を一切意識することなく、Laravelの知識だけでリッチなインタラクティブアプリケーションを構築できます。

STEP

JavaScriptの省力化

Livewireのもう一つの大きな利点は、動的なUIコンポーネントを作成する際に、JavaScriptのコードを書く必要がほとんど、あるいは全くないことです。バリデーション、リアルタイム検索、フォームの入力といった一般的な機能は、LivewireのシンプルなAPIを介して直接PHPで処理できます。これにより、フロントエンドとバックエンドのコードベースが一元化され、開発の生産性が大幅に向上します。

STEP

結論

Livewireは、フロントエンドとバックエンドの境界を曖昧にし、Laravel開発者がサーバーサイドのコードだけでフルスタックの機能を実現できるようにする、革新的なフレームワークです。複雑なJavaScriptの代わりに、Laravelのエレガントな文法でリアクティブなUIを構築できるため、開発者はユーザーエクスペリエンスに集中することができます。

Livewireの基本設定

STEP

Livewireのインストール

まずは、以下のコマンドでLivewireをインストールしましょう。

composer require livewire/livewire

このコマンドは、Livewireの依存関係をプロジェクトに追加し、必要なファイルを設定します。

STEP

コンポーネントの作成

Livewireの魔法は「コンポーネント」によって行われます。次のコマンドで新しいコンポーネントを作成します。

php artisan make:livewire Counter

これにより、Counter というPHPクラスと関連するBladeビューが下記の場所に生成されます。

  • コンポーネント:app/Http/Livewire/Counter.php
  • ビューファイル:resources/views/livewire/counter.blade.php
STEP

コンポーネントの設定

上記で生成されたコンポーネントを開き、必要なプロパティやメソッドを定義します。以下は、カウンターをインクリメントとデクリメントするメソッドを持つコンポーネントの例です。

app/Http/Livewire/Counter.php
<?php

namespace App\Http\Livewire;

use Livewire\Component;

class Counter extends Component
{
    public $count = 0;

    public function increment()
    {
        $this->count++;
    }

    public function decrement()
    {
        $this->count--;
    }

    public function render()
    {
        return view('livewire.counter');
    }
}
STEP

コンポーネントビューの設定

ビューファイル counter.blade.php は、コンポーネントのHTMLマークアップを定義します。Livewireのディレクティブを使用して、コンポーネントクラスのメソッドやプロパティと対話します。

resources/views/livewire/counter.blade.php
<div>
    <button wire:click="decrement">-</button>
    <span>{{ $count }}</span>
    <button wire:click="increment">+</button>
</div>

wire:click ディレクティブは、ボタンがクリックされたときに対応するコンポーネントクラスのメソッドを呼び出します。この場合、- ボタンは decrement メソッドを、+ ボタンは increment メソッドを呼び出します。

STEP

コンポーネントの使用

コンポーネントをページに組み込むには、そのビューファイル内で以下のように記述します。

@livewire('counter')

また、Livewireのスクリプトとスタイルを適切に読み込むために、アプリケーションのレイアウトファイル(通常は resources/views/layouts/app.blade.php)の適切な場所に以下を追加します。

resources/views/layouts/app.blade.php
<head>
    ...
    @livewireStyles
</head>
<body>
    ...
    @livewireScripts
</body>

@LivewireStyles はLivewireによって生成されるスタイルを、@LivewireScripts はJavaScriptの依存関係を読み込むために使用します。

実践例1

STEP

Sampleレイアウトテンプレートの作成

layouts/app.blade.phpのテンプレートは、JetStreamで使用しているので、別途レイアウトテンプレートとして、Sampleレイアウトテンプレートを作成します。

php artisan make:component SampleLayout

このコマンドは、App\View\Components 名前空間の下に SampleLayout コンポーネントを作成します。これにより、以下の2つのファイルが生成されます:

  • コンポーネントクラス:app/View/Components/SampleLayout.php
  • ビューファイル:resources/views/components/sample-layout.blade.php
STEP

コンポーネントクラスの編集

コンポーネントクラス( SampleLayout.php )を編集して、必要なロジックを追加します。基本的な構造は次のようになります。今回は、レイアウトテンプレートを表示(render)するだけなので、自動生成されたファイルのままでOKです。

app/View/Components/SampleLayout.php
<?php

namespace App\View\Components;

use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;

class SampleLayout extends Component
{
    /**
     * Create a new component instance.
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the view / contents that represent the component.
     */
    public function render(): View|Closure|string
    {
        return view('components.sample-layout');
    }
}
STEP

レイアウトビューファイルの修正

対応するレイアウトビューファイル( sample-layout.blade.php )にHTMLコンテンツを追加します。

resources/views/components/sample-layout.blade.php
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">

        <title>サンプル</title>

        @vite(['resources/css/app.css', 'resources/js/app.js'])

        @livewireStyles
    </head>
    <body class="font-sans antialiased">
            <main>
                {{ $slot }}
            </main>
        </div>

        @livewireScripts
    </body>
</html>
STEP

ビューファイルの作成

それでは、実際に表示するためのビューファイルをtop.blade.php名で作成します。

resources/views/top.blade.php
<x-sample-layout>
    <h1 class="text-4xl font-bold text-center my-4">Hello World</h1>
    @livewire('counter')
</x-sample-layout>
STEP

counter.blade.phpの修正

カウンターの見た目を若干修正します。

resouces/views/livewire/counter.blade.php
<div class="text-center">
    <button wire:click="decrement" class="px-4 py-2 bg-red-500 text-white font-bold rounded hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-300">
        -
    </button>
    <span class="mx-4 text-lg font-semibold">{{ $count }}</span>
    <button wire:click="increment" class="px-4 py-2 bg-green-500 text-white font-bold rounded hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-300">
        +
    </button>
</div>

ボタンをクリックして、中央の数字が増減すればOKです。

実践例2

STEP

ヘッダーメニューの作成

Livewireを使って、このサイトのようなヘッダーメニューを作成してみたいと思います。

STEP

Livewireコンポーネントの作成

Artisan CLIを使用してLivewireコンポーネントを作成します。

php artisan make:livewire HeaderMenu
STEP

コンポーネントビューの設定

コンポーネントには対応するBladeビューファイルがあり、header-menu.blade.php名で生成されます。ここにナビゲーションバーのHTMLを追加します。

Tailwind CSSを使用した基本的な例を以下に示します。

resources/views/livewire/header-menu.blade.php
<div x-data="{ isOpen: false }">
    <div class="bg-gray-800">
        <nav class="flex items-center justify-between flex-wrap py-1 px-4">
            <div class="flex items-center flex-shrink-0 text-white mr-6">
                <span class="font-semibold text-xl tracking-tight">WinRoad徒然草</span>
            </div>
            <div class="block lg:hidden">
                <button @click="isOpen = !isOpen" class="flex items-center px-3 py-2 border rounded text-teal-200 border-teal-400 hover:text-white hover:border-white">
                    <svg class="fill-current h-3 w-3" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>Menu</title><path d="M0 3h20v2H0zM0 9h20v2H0zM0 15h20v2H0z"/></svg>
                </button>
            </div>
            <div :class="{'block': isOpen, 'hidden': !isOpen}" class="w-full lg:flex lg:items-center lg:w-auto lg:justify-end">
                <div class="text-sm lg:flex-grow">
                    <a href="#" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white mr-4">
                        Flutter<br>
                        <span class="text-ms lg:text-xs text-teal-200 hover:text-white">フラッター</span>
                    </a>
                    <a href="#" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white mr-4">
                        WordPress<br>
                        <span class="text-xs lg:text-xs text-teal-200 hover:text-white">ワードプレス</span>
                    </a>
                    <a href="#" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white mr-4">
                        Laravel<br>
                        <span class="text-sm lg:text-xs text-teal-200 hover:text-white">ララベル</span>
                    </a>
                    <a href="#" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white mr-4">
                        Ubuntu<br>
                        <span class="text-sm lg:text-xs text-teal-200 hover:text-white">ウブンツ</span>
                    </a>
                    <a href="#" class="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white mr-4">
                        Swell<br>
                        <span class="text-sm lg:text-xs text-teal-200 hover:text-white">スウェル</span>
                    </a>
                </div>
            </div>
        </nav>
    </div>
</div>
STEP

レスポンシブ機能の追加

JavaScriptを使用して、小さいスクリーン上でメニューアイテムの表示を切り替えることができます。Livewireはクリックイベントをリスンし、メニューアイテムの表示を制御するプロパティを切り替えることができます。

app/Http/Livewire/HeaderMenu.php
public $isOpen = false;

public function toggleNavbar()
{
    $this->isOpen = !$this->isOpen;
}

そしてBladeビューで、ボタンを以下のように更新します。

<button @click="isOpen = !isOpen" ...>

$isOpenプロパティに基づいてメニューアイテムを条件付きでレンダリングします。

<div :class="{ 'block': isOpen, 'hidden': !isOpen }" class="hidden lg:block ...">
    <!-- ナビゲーションリンク -->
</div>
STEP

レイアウトコンポーネントに追加

メインのレイアウトファイルにLivewireコンポーネントを含めます。

@livewire('header-menu')

下記の様に表示されました。

下記はPCサイズの表示です。

下記はスマホサイズの表示です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次