Bladeコンポーネント

##Blade Componentsとは
データの受け渡し、Viewの表示などでControllerが肥大化してしまうのを防ぐためにある仕組み。
コンポーネントの機能を使うと、新しくコンポーネントクラスやBladeコンポーネントクラスを作って、機能を分け、そこにデータの受け渡しなどを任せることで、Controllerはreturn viewするだけで良くなり、負担が軽くなる。
またコンポーネント側を修正するとそのコンポーネントを使っているファイル全てに修正が反映されるのが便利。

![スクリーンショット 2021-12-16 21.03.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/770055/b98108cd-9801-3eca-7ce3-6c9f46320cb6.png)


##Bladeの種類と違い

###Blade Componentsを使わない場合(従来のBlade)

Blade Componentsを利用しない場合は、@extend, @yield, @sectionといったディレクティブを使ってレイアウトを作成する。resources¥viewsの下にlayoutsフォルダを作成しapp.blade.phpファイルを作成します。@yield, @sectionの場所にapp.blade.phpファイルを利用するBladeファイルからコンテンツが挿入される。

```php
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>@yield('title')</title>
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
  @section('sidebar')
    <p>サイドバーです。</p>
    @show

  @yield('content')
</body>
</html>
```

###Blade Componentsを使う場合
Blade Componentsを利用する場合はresources¥viewsの下にcomponentsフォルダを作成してその下にapp.blade.phpファイルを作成する。Blade Componentsを利用する場合は@yieldディレクティブではなく{{ $slot }}を使う。

```php
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Laravel Components</title>
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>
  {{ $slot }}
</body>
</html>
```

Bladeコンポーネントの記述方法は@extendsディレクティブではなくタグを利用する。利用するタグ名はx-{コンポーネント名}となる。
・resources/views/componentsフォルダ内に配置し、

```
<x-コンポーネント名>この中がslot部分に差し込まれる</x-コンポーネント名>
```

・resources/views/components/testsフォルダ内に格納している場合、

```
<x-tests.コンポーネント名></x-tests.コンポーネント名>
```
となる。

Blade Componentsでは@yieldsや@sectionディレクティブを利用するのではなくwelcome.blade.phpからのコンテンツを表示させたい部分に{{$変数}}を追加する。変数は任意の名前をつけることができ(=名前付きスロット)、ここではtitleとsidebarがそれに当たる。

```php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ $title }}</title>
  <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
</head>
<body>

  <p>サイドバーです。</p>
  {{ $sidebar }}

  {{ $slot }}
</body>
</html>
```
追加が完了したらコンテンツを渡す側のwelcome.blade.phpファイルに変更を加える。コンテンツをapp.bladee.phpに渡すwelcome.blade.phpでは、x-slotタグを利用してname属性に変数の名前を指定しタグの中に渡したいコンテンツを入力することでapp.blade.phpファイルの$titleと$sidebarの場所にコンテンツを渡すことができる。

```php
<x-app>
  <x-slot name="title">
    Laravel Components
  </x-slot>

  <x-slot name="sidebar">
    <p>サイドバーに追加できます。</p>
  </x-slot>

  <h1 class="text-2xl">Laravel Components</h1>
</x-app>
```
渡せる値などは以下のようになっている。
![スクリーンショット 2021-12-22 21.47.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/770055/47bcf800-67a3-00e2-129a-52aebfbccb65.png)




###初期値を設定する
@propsをコンポーネント側のファイルに書くことで、ブレードファイル内で値を省略した場合でもエラーが出ないようにする。

```php
//コンポーネント側
@props([
   'title',    //変数は省略しないものも全てここに記載。初期値が空でいい場合は左記。
   'message' => '初期値です。', 
   'content' => '本文の初期値です'
   ])
<div class="border-2 shadow-md w-1/4 p-2">
<div>{{ $title }}</div>
   <div>画像</div>
<div>{{ $content }}</div>
<div>{{ $message }}</div>
</div>
```
以下のようにtitle2の部分でcontentとmessageを省略した場合、コンポーネント側で設定した初期値が表示されるようになる。

```php
//Bladeファイル側
<x-tests.app>
コンポーネントテスト1

   <x-tests.card title="タイトル" content="本文" :message="$message" />
   <x-tests.card title="タイトル2" />
</x-tests.app>
```

###Attributes
CSSの属性を渡すときに使う。一部だけCSSに変更を加えたいときなどに有効。
ただ{{ $attributes }}と書くだけだと変更を加えた側のクラスが元々設定されているクラスを上書きしてしまうので、以下のような書き方にする。

```php
//コンポーネント側
@props([
   'title',
   'message' => '初期値です。', 
   'content' => '本文の初期値です'
   ])
<div {{ $attributes->merge([    //この書き方で、全てのdivタグにデフォルトで以下のクラスがつくようになる
   'class' => 'border-2 shadow-md w-1/4 p-2'
]) }} >
<div>{{ $title }}</div>
   <div>画像</div>
<div>{{ $content }}</div>
<div>{{ $message }}</div>
</div>
```

```php
//Bladeファイル側
<x-tests.app>
コンポーネントテスト1

   <x-tests.card title="タイトル" content="本文" :message="$message" />
   <x-tests.card title="タイトル2" />
   <x-tests.card title="CSSを変更したい" class="bg-red-300" />
</x-tests.app>
```


##クラスベースのコンポーネント

php artisan make:componentのコマンドを実行すると、app/View/Componentにコンポーネントクラスのファイル、とresources/views/componentsにbladeファイルがそれぞれ自動で生成される。（＊--inlineをつけるとコンポーネントクラスだけが生成される）　

ただ匿名コンポーネントと比べると無駄にクラスを挟んでいるので周りくどく、あまりメリットは見いだせない、、(変数などを分離して整理することでわかりやすくしたいとき、くらいかな使うのは)

使用する際には、app/View/Component内のクラスを指定する。
注意したいのは、クラス名がTestClassBaseであった場合、Bladeファイル内で使う場合はtest-class-baseのようにケバブケースになるという点。


クラスベースの場合、クラスなのでコンストラクタを使うことができる。そこに初期値などを格納しておく仕組みになる。

```php
<?php
//クラス側 (app/View/Component

namespace App\View\Components;

use Illuminate\View\Component;

class TestClassBase extends Component
{
    public $classBaseMessage;
    public $defaultMessage;

    //上で変数を定義し、以下のようにコンストラクタを作る。
    public function __construct($classBaseMessage, $defaultMessage = "初期値です。と")
    {
        $this->classBaseMessage = $classBaseMessage;
        $this->defaultMessage = $defaultMessage;
    }

    //コンストラクタを設定した場合こっちには特に記載に必要はない
    public function render()
    {
        return view('components.tests.test-class-base-component');
    }
}
```

```php
//コンポーネントファイル側
<x-tests.app>
   コンポーネントテスト2
　<x-test-class-base classBaseMessage="メッセージです" />
 <div class="mb-4"></div>  
　<x-test-class-base classBaseMessage="メッセージです" defaultMessage="初期値から変更してます、と。" />
</x-tests.app>
```

```php
//Bladeファイル側
<x-tests.app>
   コンポーネントテスト2
　<x-test-class-base classBaseMessage="メッセージです" />
 <div class="mb-4"></div>  
　<x-test-class-base classBaseMessage="メッセージです" defaultMessage="初期値から変更してます、と。" />
</x-tests.app>
```