React基礎講座 #3 JSXとは何か?

読了 7分

前回はViteで初めてのReactプロジェクトを作って開発サーバーを立ち上げました。その過程で私たちは自然と次のようなコードを見ました。

src/App.jsx
function App() {
  return (
    <div>
      <h1>こんにちはReact!</h1>
    </div>
  );
}

関数の中でHTMLのようなコードをそのままreturnしています。JavaScriptの中にHTMLだなんて、どこか違和感がありませんか?今回はこの不思議な構文であるJSXが何で、どう使うのかを見ていきましょう。

JSXとは何か? #

JSX(JavaScript XML) はJavaScriptにHTMLに似たマークアップ構文を組み合わせたものです。JavaScriptの公式構文ではありませんが、FacebookがReactを発表したときに一緒に提案した拡張構文であり、今日ではほぼすべてのReactプロジェクトがJSXを使っています。

実はJSXなしでもReactコードを書くことはできます。次の2つのコードはまったく同じ結果を作ります。

JSX使用
function App() {
  return <h1>Hello</h1>;
}
JSXなし
function App() {
  return React.createElement('h1', null, 'Hello');
}

上の方がはるかに読みやすいことには誰もが同意するはずです。だから私たちはJSXを使います。

ブラウザはJSXを知らない #

ブラウザのJavaScriptエンジンはJSXを直接理解できません。私たちがJSXで書いたコードはビルド過程で通常のJavaScriptに変換された後、ブラウザに渡されます。前回使ったViteのようなビルドツールがこの変換を自動で処理してくれるので、私たちは気にせずJSXを思う存分使うことができます。

JSXの基本ルール #

JSXはHTMLに似て見えますが、いくつか異なるルールがあります。初めて学ぶ方々がもっとも混乱する部分なので、順を追って見ていきます。

ルール1. 必ず1つの親要素で包まなければならない #

JSXは結局、関数が何かをreturnするものなので、一度に1つの値しか返せません。したがって、複数の要素を一度に返すには必ず1つの親で包まなければなりません。

間違った例
function App() {
  return (
    <h1>こんにちは</h1>
    <p>今日も楽しい1日をお過ごしください</p>
  );
}
正しい例
function App() {
  return (
    <div>
      <h1>こんにちは</h1>
      <p>今日も楽しい1日をお過ごしください</p>
    </div>
  );
}

<div>で包めばよいのですが、意味のない<div>が増えるのが気に入らないときがあります。そんなときは空のタグであるFragmentを使えます。

Fragment使用
function App() {
  return (
    <>
      <h1>こんにちは</h1>
      <p>今日も楽しい1日をお過ごしください</p>
    </>
  );
}

<>...</>React.Fragmentの短縮表記で、実際のDOMにはどんな要素も作らず、複数の子をまとめる役割をします。

ルール2. すべてのタグは閉じなければならない #

HTMLでは<img><br><input>のような一部のタグを閉じずに使ってもよかったです。しかしJSXではすべてのタグを閉じなければなりません。子のないタグは末尾に/を付けて自己閉じ(self-closing)で処理します。

JSX
<img src="/cat.png" alt="猫" />
<br />
<input type="text" />

ルール3. classの代わりにclassName #

HTMLでCSSクラスを指定するときに使ったclass属性はJavaScriptの予約語と重なるため、JSXではclassNameを使います。

JSX
<div className="card">カードです</div>

同じ理由で<label>for属性もhtmlForに変わります。

JSX
<label htmlFor="email">メール</label>
<input id="email" type="email" />

ルール4. 属性名はcamelCase #

HTMLでは属性名がすべて小文字でしたが(onclicktabindexreadonly)、JSXではcamelCaseを使います。

JSX
<button onClick={handleClick} tabIndex={0}>クリック</button>
<input readOnly value="固定値" />

JSXの中にJavaScriptの式を入れる #

JSXの本当の力は、マークアップの中にJavaScriptの式を自由に挟み込めることにあります。波括弧{ }の中に入るすべてのJavaScriptの式は評価されて、その結果が画面に出力されます。

src/App.jsx
function App() {
  const name = 'チョルス';
  const age = 30;

  return (
    <div>
      <h1>こんにちは{name}さん!</h1>
      <p>年齢: {age}</p>
      <p>10年後には: {age + 10}</p>
    </div>
  );
}

関数呼び出しも、三項演算子も、配列のメソッドも、すべて式であれば使えます。

src/App.jsx
function App() {
  const isLoggedIn = true;
  const items = ['りんご', 'バナナ', 'チェリー'];

  return (
    <div>
      <h1>{isLoggedIn ? 'ようこそ!' : 'ログインしてください'}</h1>
      <ul>
        {items.map(item => <li key={item}>{item}</li>)}
      </ul>
    </div>
  );
}
注記
波括弧の中には式(expression) だけが入ります。if文やforループのような文(statement) は直接入れられません。条件付き出力が必要なら三項演算子や&&演算子を、繰り返し出力が必要ならmapメソッドを使う形です。詳しい内容は#7 条件付きレンダリングと#8 リストとkeyで扱います。

インラインスタイル #

JSXで直接スタイルを指定するにはオブジェクト形式で渡します。CSSプロパティ名も同様にcamelCaseです。

src/App.jsx
function App() {
  return (
    <h1 style={{ color: 'tomato', fontSize: '32px' }}>
      スタイルが適用されたタイトル
    </h1>
  );
}

波括弧が2つあるのは最初は違和感を覚えるかもしれませんが、外側の{ }は「JSX内のJavaScriptの式」を意味し、内側の{ }は「JavaScriptのオブジェクトリテラル」だからです。

JSX内のコメント #

JSX内でコメントを書くにはJavaScriptの式なので波括弧で包まなければなりません。

src/App.jsx
function App() {
  return (
    <div>
      {/* これはJSXコメントです */}
      <h1>タイトル</h1>
    </div>
  );
}

自分でやってみる #

前回作ったプロジェクトのsrc/App.jsxを次のように変えてみてください。

src/App.jsx
function App() {
  const name = 'チョルス';
  const fruits = ['りんご', 'バナナ', 'チェリー'];

  return (
    <>
      <h1>こんにちは{name}さん!</h1>
      <p>今日の果物は全部で{fruits.length}個です:</p>
      <ul>
        {fruits.map(fruit => <li key={fruit}>{fruit}</li>)}
      </ul>
    </>
  );
}

export default App;

保存するとHMRですぐに画面が更新されるでしょう。変数の値を変えたり、配列に新しい果物を追加してみたりしながら、画面がどう反応するか直接確認してみてください。

ヒント
JSXコードを書いているときにビルドエラーが出たら、十中八九は上で扱った4つのルールのうち1つを忘れた場合です。「複数の要素を親で包んだか?」「タグをすべて閉じたか?」「classをclassNameで書いたか?」「属性をcamelCaseで書いたか?」の順序で点検してみると、ほとんど解決します。

おわりに #

今回の記事ではReactの核心構文であるJSXを紹介し、基本ルール4つ(親要素で包む、タグを閉じる、className/htmlFor、camelCase属性)、JSの式の埋め込み、インラインスタイル、コメントを見てきました。これでJSXコードを見たときの違和感がだいぶ減ったことを願います。

次の記事「React基礎講座 #4 コンポーネントとprops」では、画面を小さな単位に分ける核心概念であるコンポーネントと、コンポーネントにデータを渡す通路であるpropsを扱ってみることにしましょう。

X