ReactのFragmentってなんぞや
発端の話
業務でReactを用いた開発を担当することになり、
Reactド初心者な私が試しに触ってみたところ、以下のようなコードでエラーになりました。
function Hello() {
return (
<h1>HELLO</h1>
<p>WORLD</p>
);
}
JSXのコンポーネントには単一のルート要素を返さなければいけないという制約があり、
上記のコードの場合は2つのルート要素があるため、それが原因でエラーとなりました。
なので取り急ぎ以下のように修正したらエラーは解消されました。
function Hello() {
return (
<div>
<h1>HELLO</h1>
<p>WORLD</p>
</div>
);
}
でもこれって余計な<div>が増えちゃうよな??
取り急ぎ修正した前述のコードの<div>は画面上にも出てしまいます。
<div>
<h1>HELLO</h1>
<p>WORLD</p>
</div>
テストだったりシンプルな実装であれば気にしなくてもいいかもしれないですが、
規模感を大きめに拡張していくにあたって
- CSSのレイアウトが崩れる可能性がある
- 余計な入れ子(divだらけのDOM)になる
など、そもそも見た目にはいらないけど、
Reactの都合のためだけに存在している<div>が増えていくのはちょっとキモいですよね、、
そこで登場するのがFragment
Fragmentというのは、見た目には何も出さずに複数の要素を
1つにまとめたことにしてくれるラッパーのようなものです。
さっきの例をFragmentを用いて書き直すと以下のようになります。
function Hello() {
return (
<>
<h1>HELLO</h1>
<p>WORLD</p>
</>
);
}
<>,</>部分がFragmentで、
上記のコードがレンダリングされると以下のコードとなります。
<h1>HELLO</h1>
<p>WORLD</p>
余計な<div>を挟まずに描画することができました!
Fragmentの書き方2パターン
① 例で書いた省略パターン
function Hello() {
return (
<>
<h1>HELLO</h1>
<p>WORLD</p>
</>
);
}
<>...</>で囲みます。
たいていの場合はこれでOKだと思います。
② <React.Fragment> と書くパターン
import React from "react";
function Hello() {
return (
<React.Fragment>
<h1>HELLO</h1>
<p>WORLD</p>
</React.Fragment>
);
}
<React.Fragment>のパターンの場合、上記のようになります。
またこの場合は、宣言されたFragmentにkeyを持たせることができます。
(<>...</>には付けられません)
keyを付けたい時に使うパターン
前提としてReactは、リストの要素を描画・更新する際にkeyを使って差分を効率的に判定するため、
ループで複数要素を返すときはkeyを指定するのが推奨されています。
例えば1つのアイテムにつき<h1>と<p>を2つずつ出したい場合、以下のようになります。
import React from "react";
const items = [
{ id: 1, title: "HELLO1", body: "WORLD1" },
{ id: 2, title: "HELLO2", body: "WORLD2" },
];
function Hello() {
return (
<div>
{items.map(item => (
<React.Fragment key={item.id}>
<h1>{item.title}</h1>
<p>{item.body}</p>
</React.Fragment>
))}
</div>
);
}
<>...</>の省略記法は属性(props)を持てない仕様です。
そのため、keyなどの属性を使いたい場合は、明示的に <React.Fragment> を使う必要があります。
まとめ
- Reactコンポーネントは1つの要素だけ返すルールがあるため
<div>で包むことが多い - 余計な
<div>を増やしたくない時にFragmentを使う - 文法は2種類
- 省略記法:
<>...</> - 属性使用:
<React.Fragment key="...">...</React.Fragment>
- 省略記法:
Discussion