JSX入門:Reactの構文拡張を徹底解説—メリット・基本構文・安全な使い方とツールチェーン
JSXとは — 概要
JSX(JavaScript XML / JavaScript Syntax Extension)は、Reactで広く使われている「JavaScriptの構文拡張」です。見た目はHTMLやXMLに似ていますが、実際にはJavaScriptの式の中にUI構造を直感的に記述するための構文であり、最終的にはJavaScriptの関数呼び出し(歴史的にはReact.createElement、近年は自動ランタイムのjsx/jsxs関数など)にコンパイルされます。
なぜ使うのか(メリット)
- 可読性と表現力:UIの構造をテンプレート風に直感的に書けるため、コンポーネントの見通しが良くなる。
- JavaScriptと密接に統合:式や変数、ループ、条件分岐をそのまま組み込めるので、ロジックとテンプレートの分離に伴う煩雑さを減らせる。
- ツールチェーンとの親和性:BabelやTypeScriptが変換を担うため、型チェックやトランスパイルなどの開発ツールが使いやすい。
基本構文(サンプル)
下は簡単なJSXの例です。WordPressの投稿に貼るときは、表示させたい場合はコードタグでエスケープするのが一般的です。
<function Hello(props) {
return <div className="greeting">
Hello, {props.name}!
</div>;
}ポイント:
- HTMLに似ているが、属性名はJavaScriptのプロパティ名(camelCase)を使う(例:class -> className、for -> htmlFor)。
- テキストや式を埋め込むには波括弧 { } を使う(例:{props.name})。
- 自己終了タグは必須(<br />、<img />)。
JSXとJavaScriptの関係
JSXはブラウザでそのまま動作するわけではありません。BabelやTypeScriptなどのトランスパイラがJSXをJavaScript関数呼び出しに変換します。従来は次のようにReact.createElement呼び出しへ変換されていました:
<div className="greeting">Hello</div>は次へ変換されます:
React.createElement('div', { className: 'greeting' }, 'Hello')React 17以降では「新しいJSX変換(Automatic Runtime)」が導入され、変換後は内部的に jsx / jsxs(react/jsx-runtime)などの関数を使うようになり、明示的にReactをimportしなくてもJSXを使える設定が可能です(ただしツール側の設定が必要)。
主な特徴と注意点
- 属性名の違い:HTMLと同じに見えても属性名が異なる場合があります。class→className、for→htmlFor、style→オブジェクト(例:style={{ color: 'red' }})。
- Boolean属性:boolean属性は {true} / {false} で渡す(例:disabled={isDisabled})。
- イベントハンドラ:onClick、onChangeのようにキャメルケースで記述し、関数を渡す(例:onClick={() => doSomething()})。
- フラグメント:複数の要素を返す場合、 <React.Fragment> または短縮記法 <> </> を使える。
- 危険な挿入:生のHTMLを挿入するには
dangerouslySetInnerHTML={{ __html: '...' }}を使う。XSSのリスクがあるため注意が必要。
式、条件、繰り返し
JSX内では任意のJavaScript式を { } で埋め込めます。条件分岐は三項演算子や && を使うのが一般的です。リストを描画する際は配列の map を使い、各要素に一意の key を与える必要があります。
{items.map(item => <li key={item.id}>{item.name}</li>)} keyはReactの差分アルゴリズム(reconciliation)で要素の識別に使われ、適切に設定しないと再レンダリングで効率が落ちたり、状態が誤って引き継がれることがあります。
セキュリティ(XSS対策)
JSX自体はデフォルトでテキスト内容をエスケープしてレンダリングするため、基本的な挿入は安全です。しかし、前述の dangerouslySetInnerHTML を使うと生のHTMLが挿入され、クロスサイトスクリプティング(XSS)の脆弱性を生みます。外部入力をそのまま渡すことは避け、サニタイズが必要です。
コンパイルとツールチェーン
- Babel:従来は @babel/plugin-transform-react-jsx などで JSX を変換していました。現在は @babel/preset-react と runtime オプション(automatic/manual)で制御します。
- TypeScript:.tsx 拡張子を使い、tsconfig.json の "jsx" オプションで "react", "react-jsx"(自動ランタイム)などを指定します。
- 古いpragmaの利用:カスタムのライブラリ(例:Preact)で JSX を使う場合、変換時に別の関数(例:h)を呼ぶように pragma を指定することがあります(/** @jsx h */)。
- 自動ランタイム(React 17+):Reactの新しいJSX変換により、JSXを使う際に必ずしも React を明示的に import する必要がなくなりました(ただしツール設定が必要)。
JSXは必須か?代替はあるか
JSXは便利ですが必須ではありません。React.createElement を直接書くか、Hyperscript スタイルのAPI(preact の h など)を使うこともできます。ただし可読性やツールのサポート、エコシステムの慣習からJSXが最も一般的に採用されています。
パフォーマンス上の注意点とベストプラクティス
- キーを適切に設定して再レンダリングの無駄を防ぐ。
- 頻繁に作られる関数やオブジェクトを直接JSX内で毎回生成すると子コンポーネントが不必要に再描画される場合があるため、useCallback / useMemo を検討する。
- 大きなリストは仮想化(react-window など)でレンダリングコストを削減する。
- JSXの記述自体はコンパイル時に最適化されるため、ランタイムのオーバーヘッドは通常小さいが、冗長なコンポーネントツリーは性能に影響する。
実務でよくある落とし穴
- HTML属性名とJSX属性名の違い(class → className 等)を忘れて動かない。
- JSX内でループや条件分岐を直接書く際に key を忘れると警告やバグに繋がる。
- 危险なHTML挿入を不用意に行い、XSS脆弱性を作ってしまう。
- 自動ランタイムを使う場合、ビルド設定(Babel/TypeScript)の整合性が取れていないとコンパイルエラーになる。
他ライブラリとの互換性
JSX自体はReact専用ではありません。Preactやその他の仮想DOMライブラリもJSXを使えますが、コンパイル時のpragma指定やランタイムの差異(関数名や挙動)に注意が必要です。最近は多くのライブラリが「同じJSXを使える」互換モードを提供しています。
まとめ
JSXは、コンポーネントベースのUIを直感的に記述できる強力な構文拡張です。HTMLに似ているため学習コストが低く、JavaScriptの式と密に結びつくことで柔軟な表現が可能になります。一方で、属性名の差異や生HTML挿入の危険性、ビルド設定の整備など注意すべき点があります。最新のReactでは自動ランタイムなど使い勝手を向上させる機能も提供されているため、ツールチェーンの理解と適切なベストプラクティスの採用が重要です。


