【Laravel】 コンポーネントのクラスを活用しよう
php artisan make:component Alert
のようにしてコンポーネントを作成すると、resources
だけでなくapp/View/Component
にもファイルが作成されます。ここに作成されるコンポーネントを使用してみましょう。
Bladeコンポーネントの基本的な使い方は下の記事に載せています。
Componentクラスの基本
Componentを作る
php artisan make:component Alert
のようにartisan
を使用してコンポーネントを作成すると、ビューにコンポーネントが作成されると同時に、app/View/Components
にクラスが作成されます。
namespace App\View\Components; use Illuminate\View\Component; class Alert extends Component { /** * Create a new component instance. * * @return void */ public function __construct() { // } /** * Get the view / contents that represent the component. * * @return \Illuminate\Contracts\View\View|\Closure|string */ public function render() { return view('components.alert'); } }
<div> <!-- Life is available only in the present moment. - Thich Nhat Hanh --> </div>
render
を見ると、view
関数でコンポーネントを返しています。そのため、コントローラからview
関数を使用する時と同じ感覚で使えるということになります。
サブディレクトリに作成したい場合、php artisan make:component Hoge/Fuga
のようにします。
Componentを呼び出す
作ったコンポーネントは、bladeだけのコンポーネントと同じようにビューから呼び出すことができますが、x-クラス名
のように、クラス名をケバブケースにしたものを用います。
class Alert extends Component { // ... }
<x-alert> <!-- ... --> </x-alert>
タグに指定する名前は、app/View/Components
とresources/views/components
から対応するものが検索されます。そのため、クラスがなくても (bladeだけでも) 使用できます。クラスがある場合はクラスのほうが使用されます。
また、コンポーネントのインスタンスは、表示するコンポーネントごとに独立しています。
コンポーネントのクラスからViewに値を渡す
作成されたコンポーネントのクラスに軽く実装して、Viewのコンポーネントに値を渡してみましょう。
<div> {{ $hoge }} {{ $slot }} </div>
class Alert extends Component { // ... public function render() { $hoge = 'abcde'; return view('components.alert', compact( 'hoge', )); } }
<x-alert>slotの中身</x-alert>
そうすると、{{ $hoge }}
にはabcde
が、{{ $slot }}
にはビューで渡したDOMが表示されることが分かります。
また、クラスのコンポーネントから渡した変数名と、ビューからnameを指定した名前が被った場合 (つまり、2箇所で{{ $hoge }}
を指定したなど) 、ビューで指定したほうが優先されます。
<div> {{ $hoge }} {{ $slot }} </div>
class Alert extends Component { // ... public function render() { $hoge = 'abcde'; return view('components.alert', compact( 'hoge', )); } }
<x-alert> <!-- こっちの値が優先される --> <x-slot name="hoge">hogehoge</x-slot> slotの中身 </x-alert>
<div> hogehoge slotの中身 </div>
コンポーネントに値を渡す
今までは属性に値を入れたり、slotに値を入れ、コンポーネントでは{{ $hoge }}
のようにしてそれを表示するだけでした。クラスを使用することで、その値をコンポーネントのクラスに送ることができます。
送られた値は、コンストラクタで属性名と同じ名前の変数で取り出すことができます。ルートパラメータと違い、順番ではありません。
<x-alert hoge="aaaaa" fuga="bbbbb"> slotの中身 </x-alert>
class Alert extends Component { private $hoge; private $fuga; // ビューで属性に入れたものが入ってくる // 順番ではなく、属性名と対応する名前に入ってくる public function __construct($fuga, $hoge) { $this->fuga = $fuga; $this->hoge = $hoge; } public function render() { return view('components.alert', [ 'hoge' => $this->hoge, 'fuga' => $this->fuga, ]); } }
属性名がケバブケースの場合、変数名はキャメルケースになります。
<x-alert abc-foo="hoge">...</x-alert>
なら、__construct($abcFoo)
のようにします。
もちろん、コントローラの時と同様にモデルを取得したりといったことも可能です。
@for ($i = 1; $i <= 3; $i++) <x-alert :note-id="$i" /> @endfor
use App\Models\Note; class Alert extends Component { private $note; public function __construct($noteId) { // モデルを取得 $this->note = Note::find($noteId); } public function render() { return view('components.alert', [ 'content' => $this->note->content, ]); } }
まとめ
クラスのコンポーネントは、渡された値を様々な形で活用することで力を発揮します。例えばデータベースからデータを取得する、データを整形するなど、様々な活用方法があります。
様々な処理をコントローラではなく、コンポーネントに書いたほうが綺麗にならないか試してみましょう。
