DOMの「ゴミ」を減らせ:Fragmentで実現するクリーンなコンポーネント設計
Reactを触り始めてしばらく経つと、誰もが一度はコンソールでこんなエラーに遭遇するはずだ。「Adjacent JSX elements must be wrapped in an enclosing tag」。
「親要素で囲め」というReactのルール。駆け出しの頃は深く考えずに `
今日は、Reactにおける「Fragment」の本質と、なぜこれが単なる「記法」を超えて、アーキテクチャの品質を左右するのかを深掘りしていこう。
—
なぜ ` ` で囲むのが「罪」なのか
Reactコンポーネントが返すJSXは、最終的にブラウザ上のDOMツリーの一部となる。もし、リストアイテムを表示するコンポーネントが毎回余計な `
// 悪い例:意図しないdivのネスト
const Item = () => (
);
これがネストの深いリスト構造や、CSS Grid/Flexboxを使っているレイアウトに紛れ込むと悲惨だ。`display: flex` の直接の子要素に余計な `
「不要なDOMノード」は、メモリを食い、スタイル計算のコストを上げ、アクセシビリティ(スクリーンリーダーの読み上げ順序など)にも悪影響を及ぼす。 無意味なタグは、ただの「ノイズ」なのだ。
Fragment:DOMを汚さずにグループ化する魔法
そこで登場するのが `Fragment` だ。こいつは、「Reactのルール上、一つの親が必要だが、ブラウザ上には何も出力したくない」という、我々エンジニアの切実な願いを叶えてくれる存在だ。
1. 明示的な `` 構文
まずは基本。`import { Fragment } from ‘react’;` を経由して使用する。
import { Fragment } from ‘react’;
const UserProfile = ({ name, bio }) => (
{name}
{bio}
);
2. 短縮構文 ` … `
実務ではほぼ100%、この短縮構文を使うことになる。非常に軽快で、コードの視認性も高い。
const UserProfile = ({ name, bio }) => (
<>
{name}
{bio}
>
);
実務で「差が出る」Fragmentの使い所
Fragmentは単に囲むだけではない。現場で「お、わかってるな」と思わせる使い方が2つある。
① リストのレンダリング(keyの付与)
`map` 関数で配列を回す際、各要素を囲むためにFragmentが必要になるケースがある。その際は、短縮構文ではなく明示的な `
const List = ({ items }) => (
-
{items.map((item) => (
- {item.term}
- {item.description}
// keyが必要な場合は短縮構文は使えない!ここが落とし穴
))}
);
多くの人が `<> … >` にkeyを渡そうとしてエラーにハマる。`key` を渡す必要があるときは必ず `
② 条件分岐でのグループ化
条件によって複雑な要素を出し分ける際、Fragmentを使えば親の `div` を排除しつつ、ロジックをきれいに保てる。
const ConditionalUI = ({ isLoggedIn, user }) => (
// フラグメントで囲むことで、divを増やさずに複数の要素を返せる
<>
>
) : (
)}
);
—
最後に:シニアエンジニアからの視点
ブラウザは仮想DOMの情報を元に、最終的にネイティブなDOMツリーを構築する。Fragmentを使うことは、「ブラウザに対して無駄な構造を押し付けない」という、パフォーマンスと保守性への敬意だ。
「とりあえずdivで囲んでおこう」という雑な開発は、いつか必ずCSSの衝突や、謎のレイアウト崩れという形で君に牙を剥く。
コードを書くとき、一度立ち止まって考えてみてほしい。「このdivは本当に必要か?」。その問いかけができるようになった時、君の書くReactコンポーネントは、劇的に洗練されるはずだ。
さあ、エディタを開いて、プロジェクト内の不要な `

コメント