JSXはJavaScript XMLの略で、開発者がJavaScriptファイルにHTMLなどのコードを書けるようにするReactで便利な構文拡張です。
特にJSXを使い始めたばかりの頃は、「JSX expressions must have one parent element」(JSX式には親要素が1つ必要です)というエラーメッセージに遭遇することがあります。このエラーは、複数の要素が親要素でラップされずに1つの式で返された場合に発生します。
また、類似のエラーメッセージに、「Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>…</>?」(隣接するJSX要素は、タグで囲む必要があります)もあります。
今回はReact開発者向けに、このエラーの解決方法をいくつかご紹介していきます。
「JSX expressions must have one parent element」エラーの原因
JSXには、常に単一の要素を返すというルールがあります。このルールはReactにも適用され、どのコンポーネントも単一のルート要素しか返せません。
これは、コンポーネントのレンダリングの際に、最終的にページにレンダリングするHTMLに対応した仮想DOMツリーが作成されるためです。JSXに複数のルート要素があると、Reactがそれらを処理することができず、「JSX expressions must have one parent element」や「Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>…</>?」のようなエラーメッセージを返します。
例えば、以下のJSXコードのレンダリングを試行してみます。
function App() {
return (
<h1>Hello, world!</h1>
<p>これは段落です。</p>
)
}
すると以下のような「JSX expressions must have one parent element」エラーメッセージが表示されます。
または以下のような「Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>…</>?」エラーメッセージになることもあります。
これらのエラーは、2つのルート要素(<h1>
と<p>
)が返されているために発生します。
JSXは複数の値を返すことができないため、関数と同じように動作します(配列で囲まれている場合を除く─配列は1つの値とみなされる)。
function myFunc() {
return value1;
return value2;
}
上記の関数では1つ目のreturn文が常に実行されるため、2つ目のreturn文まで到達しません。
「JSX expressions must have one parent element」エラーを解決する(3つの方法)
このエラーを解決する方法は、大きく分けて3つあります。
- Divタグでラップする
- Fragment(<>と</>)でラップする
- React.Fragmentコンポーネントを使用する
1. すべての要素をDivタグでラップする
このエラーを解決する最も簡単な方法は、複数のJSX要素を<div>などの1つの親要素でラップすることです。
要素を1つのまとまりとしてグループ化することで、レンダリングすることができます。以下、例を見てみましょう。
function App() {
return (
<div>
<h1>Hello, world!</h1>
<p>これは段落です。</p>
</div>
)
}
上の例では、<h1>
と<p>
要素が、親要素となる<div>
要素でラップされています。
2. すべての要素をFragmentでラップする
エラーメッセージ「JSX expressions must have one parent element」または「Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>…</>?」を解決するもう1つの方法では、JSX Fragmentを使用します。
Fragment(フラグメント)はReactの組み込み機能で、DOMに余分なノードを追加することなく、子要素のリストをグループ化します。これにより、レンダリングされるHTMLに余計なDOMノードを加えず、複数の要素を単一の親要素でラップすることができます。例を見てみます。
function App() {
return (
<>
<h1>Hello, world!</h1>
<p>これは段落です。</p>
</>
)
}
JSX Fragment(<>と</>)を使用して複数の要素をラップしており、このFragmentは親要素として機能します。
3. すべての要素をReact.Fragmentでラップする
最後に、通常の要素の代わりにReact.Fragment
要素を使用することもできます。
これは、Fragmentと同じように機能しますが、もう少し明示的で、親要素に特定のキーやその他のプロパティを与えたい場合に便利です。例は以下のとおりです。
function App() {
return (
<React.Fragment>
<h1>Hello, world!</h1>
<p>これは段落です。</p>
</React.Fragment>
)
}
上の例では、親要素として通常の要素の代わりに、React.Fragment
を使用しています。複数の要素を <></>で囲むことで、レンダリングされるHTMLに余計なノードを追加することなく、要素をグループ化できます。
React.Fragment
コンポーネントを使用するには、Reactをインポートする必要があります。また、Fragment自体にpropsやclassName
、style
、id
を追加することができるため、Fragment内の要素のグループにスタイルなどの属性を適用したい場合に有用です。
条件文の「JSX expressions must have one parent element」エラーを解決する
Reactで条件付き三項演算子を扱う場合にも、「JSX expressions must have one parent element」や「Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>…</>?」のようなエラーメッセージが表示されることがあります。
これは、条件文の中から複数の要素が返された場合に発生します。この場合、Reactが正しくレンダリングを行うことができず、いずれかのエラーを返します。
function App() {
return (
<div>
{condition ? (
<h1>見出し1</h1>
<p>段落1</p>
) : (
<h2>見出し2</h2>
<p>段落2</p>
)}
</div>
)
}
このエラーも、今回ご紹介した3つの方法のいずれかで解決可能です。Fragment(<>
と</>
)または<div>
要素を使用するのがお勧めです。
function App() {
return (
<div>
{condition ? (
<>
<h1>見出し1</h1>
<p>段落1</p>
</>
) : (
<>
<h2>見出し2</h2>
<p>段落2</p>
</>
)
}
</div>
)
}
まとめ
エラーメッセージ「JSX expressions must have one parent element」または「Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>…</>?」は、React初心者が遭遇しがちな問題です。
<div>
要素を使用するのが最も簡単な解決策ですが、DOMに不要なdivタグを追加することになります。Fragmentを使用すれば、DOMに余計なノードを追加することなく、すっきりエラーを解決することができます。
この問題に遭遇した経験はありますか?また、今回ご紹介したもの以外にも解決策をご存知でしたら、以下のコメント欄でぜひお聞かせください。