【実務・中級編】 Propsスプレッドの安全性と注意点 – React実践ガイド

Propsスプレッドの「沼」にハマるな:安全なコンポーネント設計の極意

Reactを書いていると、ついやってしまうのが `{…props}` という記述。いわゆる「Propsスプレッド」だ。
「とりあえずこれで全部渡しておけば楽だし、型も通るから大丈夫でしょ?」

もし君がそう思っているなら、一度立ち止まってほしい。その「便利さ」は、将来の自分やチームメンバーに「予期せぬバグという名の借金」を背負わせている可能性があるからだ。今日は、この Props スプレッドとどう正しく付き合うか、現場レベルの極限の知見を共有しよう。

—

なぜPropsスプレッドは危険なのか?

ブラウザの裏側の話をしよう。JSXで `{…props}` を書くと、Reactはそのオブジェクトを分解してコンポーネントのプロパティとして展開する。これは非常に強力だが、同時に「意図しないPropsのリーク」を招く。

例えば、`CustomButton` コンポーネントに `onClick` を渡すつもりで `{…props}` を使ったとする。もし親から `id` や `data-testid`、あるいは余計な `className` や `style` が混入していたらどうなるか? DOMに不要な属性が紛れ込み、CSSの衝突や、ブラウザのレンダリング最適化を阻害する原因になる。

特にTypeScriptを使っている場合、`any` や広すぎる型定義でスプレッドを強行するのは「型安全という名の免罪符」でしかなく、実質的には型ガードを放棄しているのと同義だ。

—

実践:安全にPropsを扱うための「分離と抽出」

現場では「受け取ったPropsをそのまま流す」のではなく、「必要なものだけを抜き出し、残りをフォールスルーさせる」というパターンを徹底する。

まずは、最も洗練された「Propsの分離」の例を見てほしい。

import React, { ComponentPropsWithoutRef } from ‘react’;

// コンポーネントのProps型定義
// ComponentPropsWithoutRefを使うと、refを自動的に除外した標準的なHTML属性が取得できる
type ButtonProps = ComponentPropsWithoutRef<'button'> & {
variant?: ‘primary’ | ‘secondary’; // 独自のカスタムProp
};

export const SecureButton = ({
variant = ‘primary’,
className,
…rest // 残りの属性をここにまとめる
}: ButtonProps) => {

// 1. 独自のロジックでクラス名を制御
const baseClass = “px-4 py-2 rounded transition-all”;
const variantClass = variant === ‘primary’ ? “bg-blue-600 text-white” : “bg-gray-200”;

return (

);
};

このコードがなぜ優れているのか?

1. `ComponentPropsWithoutRef<'button'>` の活用: これを使うことで、HTMLボタンが本来受け取るすべての属性(`disabled`, `type`, `aria-`など)を型安全に継承しつつ、`ref` の扱いを明示的に制御できる。
2. Destructuring(分割代入)の活用: `…rest` に渡す前に、必要なProp(`variant` や `className`)を事前に抜き出している。これにより、DOMに「使わないProp」が渡されるリスクをゼロにしている。

—

注意すべき「アンチパターン」

逆に、現場で見ていて「あ、これはすぐ直そう」と思うのがこれだ。

// アンチパターン
const DangerousComponent = (props: any) => {
return

; // 全てを垂れ流している
};

これの何が悪いか? `props` に何を渡しても受け入れてしまうため、親が間違えて `color=”red”`(HTMLのdivタグには無効な属性)を渡してもTypeScriptは沈黙する。結果、ブラウザのコンソールに「Unknown DOM property」という警告が並ぶことになる。これではデバッグの難易度が跳ね上がる。

—

シニアからのアドバイス:限界まで安全にするために

もし君が大規模なプロジェクトに携わっているなら、以下のルールをチームに導入することを推奨する。

1. 「とりあえず …props」を禁止する: PRレビューで「このスプレッド、本当に全部必要?」と問いかけるだけで、コードの品質は劇的に上がる。
2. HTML属性を明示的に継承する: `interface` で適当に型を定義せず、`ComponentPropsWithoutRef` を活用して、ブラウザのネイティブ仕様に準拠させる。
3. 不要なPropは明示的に捨てる: もし特定のPropをDOMに渡したくない場合は、分割代入で受け取った後に、意図的に無視する。

// 特定のPropだけを渡したくない場合のテクニック
const { someDangerousProp, …safeProps } = props;
return

;

まとめ:道具としてのPropsスプレッド

Propsスプレッドは、Reactという道具箱の中でも非常に鋭利なカッターだ。使い方を間違えれば自分を傷つけるが、正しく使えばこれ以上なく効率的にコードを書ける。

「楽をするためのスプレッド」ではなく、「保守性を高めるためのスプレッド」を目指してほしい。次にコードを書くとき、その `{…props}` が本当に「全て」必要なのか、一度だけ考えてみてくれ。そのわずかな思考の積み重ねが、数年後に生き残る堅牢なフロントエンド基盤を作るはずだ。

さあ、エディタに戻って、少しだけコードを「清掃」してみようか。

コメント

タイトルとURLをコピーしました