Laravel ショーツ - ブレード コンポーネントの落とし穴


更新 2021-10-22
GitHub で問題が作成されました: https://github.com/laravel/framework/issues/39232

そして修正がマージされました:
https://github.com/laravel/framework/pull/39319

Blade components は、ビュー テンプレートを再利用可能な小さな断片に構造化するための優れたツールです.しかし、彼らと一緒に仕事をしているうちに、知っておくべき落とし穴に出くわしました.まず、この匿名コンポーネントを見てみましょう.

post-title.blade.php

@props(['post'])
<h1 {{ $attributes }}>{{ $post->title }}</h1>


たとえば、投稿一覧ページで使用する方法は次のとおりです.

@foreach ($posts as $post)
  <x-post-title :post="$post" />
@endforeach


この例では、投稿は以前にデータベースからロードされた Eloquent モデルです.さて、このコードを実行すると、特に奇妙なことは何もありません.すべてが意図したとおりに機能します.ただし、もう少し深く掘り下げると、予期しない動作がいくつか見つかります.

コンポーネントがインスタンス化されるたびに、投稿モデルが JSON にシリアライズされます.

この動作の原因は、Blade コンポーネント コンパイラが sanitizeComponentAttribute 関数内の属性を処理する方法にあります.

CompilesComponents.php

/**
 * Sanitize the given component attribute value.
 *
 * @param  mixed  $value
 * @return mixed
 */
public static function sanitizeComponentAttribute($value)
{
    return is_string($value) ||
           (is_object($value) && ! $value instanceof ComponentAttributeBag && method_exists($value, '__toString'))
                    ? e($value)
                    : $value;
}


基本的に、__toString 関数を実装するオブジェクトはすべて文字列に変換されます. Eloquent モデルの場合、これにより JSON に変換されます.モデルの大きさとコンポーネントの使用頻度によっては、使用されない JSON 文字列の作成に大量のリソースが浪費されます.

解決策: クラス ベースのコンポーネントを使用する



匿名コンポーネントの代わりに、クラス ベースのコンポーネントを使用し、props をコンストラクター引数に追加します.これを行うと、オブジェクトは文字列に変換されなくなります.

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class PostTitle extends Component
{
    public $post;

    public function __construct($post)
    {
        $this->post = $post;
    }

    public function render()
    {
        return view('components.post-title');
    }
}



投稿 Laravel shorts – Blade component gotchahbgl に最初に表示されました.