2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel】@propsなしのBladeコンポーネントが地味に危険な理由

2
Last updated at Posted at 2026-06-03

この記事の目的

  • Bladeコンポーネントで@propsを宣言する理由をちゃんと理解する
  • 宣言サボると HTMLが太る + データ漏洩 するという話
  • 元ネタは @PovilasKorop さんのポスト。良い小ネタだったので布教します

そもそも何が起きるん?

こういうコンポーネントを呼び出したとします。modelclass を渡してるだけのよくあるやつ。

// modelが属性としてバインドされる
<x-forms.input :model="$myModel" class="font-bold" />

問題は呼び出される側、resources/views/components/forms/input.blade.php の書き方です。

BEFORE:@propsを書いてない

// resources/views/components/forms/input.blade.php
// BEFORE: NO PROPS
<div {{ $attributes->merge(['class' => 'rounded border']) }}>
    <input type="text" />
</div>

一見ちゃんと動きそうですよね。class はええ感じにマージされます。

問題はmodelの方です。

Laravelでは コンポーネント側で明示的に受け取らなかった属性は、ぜんぶ$attributesに残ったまま になります。
で、$attributes->merge() はその中身をそのままHTML属性として吐き出してしまいます。

結果のHTML(地獄)

$myModelがEloquentモデルやと、JSONにシリアライズされてこうなります👇

// RESULT HTML:
<div class="rounded border font-bold"
     model="{&quot;id&quot;:22,&quot;client_id&quot;:19,&quot;provider_id&quot;:14,&quot;updated_at&quot;:&quot;2026-05-22T06:43:45.000000Z&quot;,&quot;created_by_user_id&quot;:160}">
    <input type="text" />
</div>

はい、モデルまるごとHTMLに埋め込まれてます。これがマズい理由は2つ。

注意

  1. HTMLが太る … モデル全体が文字列でベタ書きされるので、無駄にページが重くなる
  2. データ漏洩client_idprovider_idcreated_by_user_id みたいな、ユーザーに見せる必要ない内部情報がページのソースに丸見え

id だけならまだしも、内部の外部キーやら作成者IDやらがそのまま出てるの、普通にアカンやつです。

AFTER:@propsで受け取る

直し方は簡単。コンポーネントの先頭で@propsを宣言するだけ。

// resources/views/components/forms/input.blade.php
// AFTER: WITH PROPS
@props(['model'])

<div {{ $attributes->merge(['class' => 'rounded border']) }}>
    <input type="text" />
</div>

@props(['model']) と書くと、model$attributesから引っこ抜かれます
なのでmerge()の出力にはもう含まれません。

きれいなHTML

// CLEAN HTML:
<div class="rounded border font-bold">
    <input type="text" />
</div>

スッキリ🔥 漏洩もなし、無駄な肥大化もなし。

因みに、@propsで宣言した値はコンポーネント内で普通に変数として使えます。

@props(['model'])

<div {{ $attributes->merge(['class' => 'rounded border']) }}>
    <input type="text" value="{{ $model->name }}" />
</div>

宣言する=「これはコンポーネントが使うデータやで」と意思表示することなので、$attributes(=そのままDOMに出る属性)と役割がきっちり分かれる、というわけです。

まとめ

  • コンポーネントに渡す値は、属性かプロパティかを意識して @propsで明示宣言する
  • サボると$attributes->merge()が未宣言の値を全部HTMLに垂れ流す
  • 結果、HTMLが太るしモデルの中身が漏れる
  • 地味やけど事故ると普通にヤバいので、コンポーネント書くときは@props忘れないように!

以上、小ネタでした。$attributesまわり、なんとなくで書いてると足元すくわれるので気をつけましょ〜。

@ Propsについて

スクリーンショット 2026-06-03 15.14.08.png

@props の役割は2つあります。

  • 「この属性はデータ変数として扱う」という宣言。
    • @props(['model']) と書けば、渡した値をコンポーネント内で $model として使えます。
  • 宣言した prop は $attributes(属性バッグ)から引き抜かれること。
    • だから $attributes->merge() してもHTMLに出てきません。
    • 逆に宣言しなかった属性は $attributes に残り、merge() でそのままDOMに出力される。

「attributeから値を取り出して変数化する」という理解でOK

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?