Reactのフラグメントを使う理由|不要なdivを避ける方法

ReactのFragmentを使って不要なdivを避ける方法を詳しく解説。React.Fragment、短縮記法、key属性の使い方まで実例付きで説明します。

Learning Next 運営
25 分で読めます

みなさん、Reactでコードを書いていますか?

「コンポーネントを作る時、いつも余計なdivで囲んでしまう」「DOM に無意味なdivがたくさん作られてしまう」と悩んだことはありませんか?

この記事では、Reactの**Fragment(フラグメント)**を使って不要なdivを避ける方法をお伝えします。 基本的な使い方から実践的な活用方法まで、分かりやすく解説していきますね。

Reactフラグメントって何?

まずは、フラグメントがどんなものかを理解しましょう。

なぜフラグメントが必要なの?

Reactのコンポーネントには、大きな制約があります。 それは、一度に一つの要素しか返せないということです。

// ❌ エラー:複数の要素を直接返せない
function BrokenComponent() {
return (
<h1>タイトル</h1>
<p>説明文</p>
);
}

この書き方をすると、エラーが出てしまいます。 「複数の要素は、何かで囲んでくださいね」とReactに怒られちゃうんです。

従来は、divで囲んで解決していました:

// ❌ 動くけど、不要なdivが生成される
function WrappedComponent() {
return (
<div> {/* この div は本当に必要? */}
<h1>タイトル</h1>
<p>説明文</p>
</div>
);
}

確かに動きます。 でも、このdivって本当に必要でしょうか?

不要なdivが引き起こす問題

余計なdivは、いろいろな問題を引き起こします。

DOM構造が汚くなる

<!-- 不要なdivがたくさん -->
<div> <!-- App -->
<div> <!-- Header -->
<div> <!-- Navigation -->
<div> <!-- NavItem -->
<a href="/">ホーム</a>
</div>
<div> <!-- NavItem -->
<a href="/about">について</a>
</div>
</div>
</div>
</div>

CSSレイアウトが期待通りに動かない

.container {
display: flex;
justify-content: space-between;
}
/* 不要なdivのせいで、セレクタが複雑になる */
.container > div > .item {
flex: 1;
}

このように、余計なdivがあると開発が大変になってしまいます。

フラグメントで解決!

そこで登場するのがフラグメントです。

// ✅ フラグメントを使った解決法
function CleanComponent() {
return (
<React.Fragment>
<h1>タイトル</h1>
<p>説明文</p>
</React.Fragment>
);
}

フラグメントを使うと、余計なdivなしで複数の要素をまとめられます。

フラグメントの基本的な使い方

フラグメントには、いくつかの書き方があります。

React.Fragmentを使う方法

一番基本的な書き方です:

import React from 'react';
function UserProfile() {
return (
<React.Fragment>
<h2>ユーザープロフィール</h2>
<p>名前: 田中太郎</p>
<p>年齢: 25</p>
<p>職業: エンジニア</p>
</React.Fragment>
);
}

この書き方では、React.Fragmentで複数の要素を囲んでいます。 実際に画面に表示されるHTMLを見てみましょう:

<!-- 余計なdivがない! -->
<h2>ユーザープロフィール</h2>
<p>名前: 田中太郎</p>
<p>年齢: 25歳</p>
<p>職業: エンジニア</p>

きれいですね! 不要なdivがなくて、とてもスッキリしています。

短縮記法(空タグ)

もっと簡単に書ける方法もあります:

function UserProfile() {
return (
<>
<h2>ユーザープロフィール</h2>
<p>名前: 田中太郎</p>
<p>年齢: 25</p>
<p>職業: エンジニア</p>
</>
);
}

<></>だけで、フラグメントを表現できます。 とても短くて便利ですよね。

注意点もあります

この短縮記法には、ちょっとした制限があります:

  • 古い開発ツールでは対応していない場合がある
  • key属性を使えない(後で詳しく説明します)

フラグメントとdivの比較

同じコンポーネントを、2つの方法で書き比べてみましょう:

// divを使った場合
function WithDiv() {
return (
<div> {/* この div は必要? */}
<dt>名前</dt>
<dd>田中太郎</dd>
<dt>年齢</dt>
<dd>25</dd>
</div>
);
}
// フラグメントを使った場合
function WithFragment() {
return (
<>
<dt>名前</dt>
<dd>田中太郎</dd>
<dt>年齢</dt>
<dd>25</dd>
</>
);
}

生成されるHTMLも比較してみましょう:

<!-- divを使った場合 -->
<div>
<dt>名前</dt>
<dd>田中太郎</dd>
<dt>年齢</dt>
<dd>25歳</dd>
</div>
<!-- フラグメントを使った場合 -->
<dt>名前</dt>
<dd>田中太郎</dd>
<dt>年齢</dt>
<dd>25歳</dd>

フラグメントの方が、HTMLがスッキリしていますね。 定義リスト(dl要素)の子要素として正しい構造になっています。

実際の開発での活用例

フラグメントが活躍する場面を、具体例で見てみましょう。

テーブルの行で使う

テーブルのセルを作る時に、フラグメントがとても便利です:

function UserTableRow({ user }) {
return (
<>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.role}</td>
</>
);
}
function UserTable({ users }) {
return (
<table>
<thead>
<tr>
<th>ID</th>
<th>名前</th>
<th>メール</th>
<th>役職</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<UserTableRow user={user} />
</tr>
))}
</tbody>
</table>
);
}

UserTableRowコンポーネントでは、複数のtd要素をフラグメントでまとめています。 もしdivで囲んでしまうと、テーブルの構造が壊れてしまうんです。

フォームのフィールドをまとめる

フォームの入力欄をグループ化する時にも活躍します:

function PersonalInfoFields() {
return (
<>
<div className="field">
<label></label>
<input type="text" name="lastName" />
</div>
<div className="field">
<label></label>
<input type="text" name="firstName" />
</div>
<div className="field">
<label>生年月日</label>
<input type="date" name="birthDate" />
</div>
</>
);
}
function ContactInfoFields() {
return (
<>
<div className="field">
<label>メールアドレス</label>
<input type="email" name="email" />
</div>
<div className="field">
<label>電話番号</label>
<input type="tel" name="phone" />
</div>
</>
);
}

こうすると、関連するフィールドをコンポーネントで分けられます。 でも余計なdivは作らずに済みますね。

function UserForm() {
return (
<form>
<fieldset>
<legend>個人情報</legend>
<PersonalInfoFields />
</fieldset>
<fieldset>
<legend>連絡先</legend>
<ContactInfoFields />
</fieldset>
</form>
);
}

ナビゲーションメニューで使う

メニューの項目をまとめる時にも便利です:

function MainNavigation() {
return (
<>
<a href="/" className="nav-link">ホーム</a>
<a href="/about" className="nav-link">について</a>
<a href="/services" className="nav-link">サービス</a>
<a href="/contact" className="nav-link">お問い合わせ</a>
</>
);
}
function UserNavigation({ isLoggedIn, user }) {
if (!isLoggedIn) {
return (
<>
<a href="/login" className="nav-link">ログイン</a>
<a href="/register" className="nav-link">登録</a>
</>
);
}
return (
<>
<span className="nav-user">ようこそ、{user.name}さん</span>
<a href="/profile" className="nav-link">プロフィール</a>
<a href="/logout" className="nav-link">ログアウト</a>
</>
);
}

ログイン状態によって表示を変えている例です。 フラグメントを使うことで、余計なdivなしに切り替えられます。

key属性が必要な時の対処法

リストを作る時は、key属性が必要になります。 そんな時の書き方を見てみましょう。

key属性の基本

リストをレンダリングする時は、必ずkey属性を指定する必要があります:

function CommentList({ comments }) {
return (
<div className="comments">
{comments.map(comment => (
<React.Fragment key={comment.id}>
<dt className="comment-author">{comment.author}</dt>
<dd className="comment-content">{comment.content}</dd>
<dd className="comment-date">{comment.date}</dd>
</React.Fragment>
))}
</div>
);
}

key属性を使う時は、短縮記法(<>)は使えません。 React.Fragmentと書く必要があります。

なぜかというと、短縮記法では属性を指定できないからです。

複雑なリストの例

もう少し複雑な例も見てみましょう:

function ProductCatalog({ categories }) {
return (
<div className="catalog">
{categories.map(category => (
<React.Fragment key={category.id}>
<h2 className="category-title">{category.name}</h2>
<p className="category-description">{category.description}</p>
<div className="products">
{category.products.map(product => (
<div key={product.id} className="product">
<h3>{product.name}</h3>
<p>{product.price}</p>
</div>
))}
</div>
</React.Fragment>
))}
</div>
);
}

このように、カテゴリごとにタイトル、説明、商品リストをまとめて表示しています。 フラグメントを使うことで、余計なdivなしに構造化できています。

使い分けのコツ

短縮記法を使う場面

// key属性が不要な場合
function SimpleComponent() {
return (
<>
<h1>タイトル</h1>
<p>内容</p>
</>
);
}

React.Fragmentを使う場面

// key属性が必要な場合
function ListComponent({ items }) {
return (
<div>
{items.map(item => (
<React.Fragment key={item.id}>
<h3>{item.title}</h3>
<p>{item.description}</p>
</React.Fragment>
))}
</div>
);
}

条件によって表示を切り替える

フラグメントは、条件付きレンダリングでも活躍します。

条件によって複数要素を表示

function UserCard({ user, showDetails, showActions }) {
return (
<div className="user-card">
<h3>{user.name}</h3>
<p>{user.email}</p>
{showDetails && (
<>
<p>部署: {user.department}</p>
<p>入社日: {user.joinDate}</p>
<p>役職: {user.position}</p>
</>
)}
{showActions && (
<>
<button>編集</button>
<button>削除</button>
<button>詳細表示</button>
</>
)}
</div>
);
}

showDetailstrueの時だけ、詳細情報を表示しています。 showActionstrueの時だけ、ボタンを表示しています。

フラグメントを使うことで、余計なdivなしに条件分岐ができますね。

動的にフォームを作る

フラグメントを使って、動的にフォームを作ることもできます:

function DynamicForm({ fields }) {
const renderField = (field) => {
switch (field.type) {
case 'text':
return (
<>
<label htmlFor={field.name}>{field.label}</label>
<input
type="text"
id={field.name}
name={field.name}
placeholder={field.placeholder}
/>
</>
);
case 'select':
return (
<>
<label htmlFor={field.name}>{field.label}</label>
<select id={field.name} name={field.name}>
{field.options.map(option => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</>
);
default:
return null;
}
};
return (
<form>
{fields.map(field => (
<div key={field.name} className="form-field">
{renderField(field)}
{field.helpText && (
<small className="help-text">{field.helpText}</small>
)}
</div>
))}
</form>
);
}

この例では、フィールドのタイプによって表示する要素を切り替えています。 各タイプでlabelinput(またはselect)をフラグメントでまとめています。

よくある間違いと対処法

フラグメントを使う時によくある間違いを見てみましょう。

間違い1: 単一要素にフラグメント

// ❌ 間違い:単一要素をフラグメントで囲む
function SingleElement() {
return (
<>
<div>これは単一要素です</div>
</>
);
}
// ✅ 正しい:単一要素は直接返す
function SingleElement() {
return <div>これは単一要素です</div>;
}

要素が一つだけの場合は、フラグメントは不要です。 直接その要素を返しましょう。

間違い2: keyが必要なのに短縮記法を使用

// ❌ 間違い:key属性が必要なのに短縮記法
function BadList({ items }) {
return (
<div>
{items.map(item => (
<> {/* keyを指定できない */}
<h3>{item.title}</h3>
<p>{item.content}</p>
</>
))}
</div>
);
}
// ✅ 正しい:React.Fragmentでkey属性を指定
function GoodList({ items }) {
return (
<div>
{items.map(item => (
<React.Fragment key={item.id}>
<h3>{item.title}</h3>
<p>{item.content}</p>
</React.Fragment>
))}
</div>
);
}

リストの場合は、必ずkey属性が必要です。 短縮記法ではkeyを指定できないので、React.Fragmentを使いましょう。

間違い3: CSSスタイリングの問題

// ❌ 問題:フラグメントにはスタイルを適用できない
function StyledFragment() {
return (
<> {/* CSSクラスやスタイルは適用できない */}
<h2>タイトル</h2>
<p>内容</p>
</>
);
}
// ✅ 解決策1: 適切な要素で囲む
function StyledComponent() {
return (
<div className="content-section">
<h2>タイトル</h2>
<p>内容</p>
</div>
);
}
// ✅ 解決策2: 個別にスタイルを適用
function IndividuallyStyled() {
return (
<>
<h2 className="title">タイトル</h2>
<p className="content">内容</p>
</>
);
}

フラグメント自体には、CSSクラスやスタイルを適用できません。 スタイリングが必要な場合は、適切な要素で囲むか、個別の要素にスタイルを適用しましょう。

パフォーマンスへの影響

フラグメントは、パフォーマンスにも良い影響があります。

DOM要素数の削減

たくさんのアイテムをレンダリングする場合を考えてみましょう:

// divを使用(2000個のDOM要素)
function ItemListWithDiv({ items }) {
return (
<div>
{items.map(item => (
<div key={item.id}> {/* 不要なdiv = 1000個 */}
<span>{item.name}</span> {/* span = 1000個 */}
</div>
))}
</div>
);
}
// フラグメントを使用(1000個のDOM要素)
function ItemListWithFragment({ items }) {
return (
<div>
{items.map(item => (
<React.Fragment key={item.id}>
<span>{item.name}</span> {/* span = 1000個のみ */}
</React.Fragment>
))}
</div>
);
}

1000個のアイテムがある場合、フラグメントを使うとDOM要素を半分に減らせます。 これは、メモリ使用量やレンダリング速度の改善につながります。

メモリ使用量の改善

大きなテーブルの例を見てみましょう:

function LargeDataTable({ data }) {
return (
<table>
<tbody>
{data.map(row => (
<tr key={row.id}>
<> {/* フラグメントでtd要素を直接レンダリング */}
<td>{row.id}</td>
<td>{row.name}</td>
<td>{row.email}</td>
<td>{row.department}</td>
<td>{row.position}</td>
</>
</tr>
))}
</tbody>
</table>
);
}

10,000行のテーブルの場合を考えてみます:

  • divを使用: 60,000個のDOM要素(div + td × 5)
  • フラグメント使用: 50,000個のDOM要素(td × 5のみ)

約16%のDOM要素削減ができます。 これは大きな改善ですね!

まとめ

Reactのフラグメントについて、詳しく解説しました。

フラグメントの基本ポイント

  • 複数の要素をグループ化できる仕組み
  • 不要なdiv要素を避けることができる
  • DOM構造をきれいに保てる

2つの書き方がある

  1. React.Fragment - key属性が使える
  2. 短縮記法(<>) - 簡潔だがkey属性は使えない

使い分けのルール

// key属性が不要な場合
<>
<element1 />
<element2 />
</>
// key属性が必要な場合
<React.Fragment key={item.id}>
<element1 />
<element2 />
</React.Fragment>
// スタイリングが必要な場合
<div className="styled-wrapper">
<element1 />
<element2 />
</div>

活用場面

  • テーブルの行要素
  • フォームフィールドのグループ化
  • ナビゲーションメニュー
  • 条件付きレンダリング

パフォーマンスの利点

  • DOM要素数の削減
  • メモリ使用量の改善
  • レンダリング速度の向上

注意すべきポイント

  • 単一要素には不要
  • key属性が必要な場合はReact.Fragmentを使用
  • フラグメント自体にはCSSスタイルを適用できない

フラグメントを適切に使うことで、よりクリーンで高性能なReactアプリケーションを作ることができます。 ぜひ今日から使ってみてくださいね!

関連記事