従来、開発者はマークアップとロジックを別々のファイルに分け、構造にはHTML、スタイリングにはCSSを使用し、インタラクションやデータ操作にはJavaScriptを記述してきました。

しかし、これらの技術を組み合わせることで、開発プロセスを簡素化し、複雑なユーザーインターフェースを簡単に構築できる方法があるとしたらどうでしょうか。そこで登場するのがJSXです。

この記事では、JSXとは何か、どのように機能するのか、そしてなぜウェブ開発において、これが動的なユーザーインターフェースを構築するために重要なのかを学びます。

この革命的な技術について、詳しく見てみましょう。

JSXとは

JSX(JavaScript XML)は、JavaScriptの構文拡張で、JavaScriptファイル内にHTMLのようなコードを記述できるようにするものです。Meta(旧Facebook)によって開発されました。

JSXの構文はHTMLに似ており、開閉タグ、属性、入れ子要素などがあります。

たとえば、次のようなJSXコードを書いて、単純な見出し要素を表示することができます。

const heading = <h1>Hello, JSX!</h1>;

このコードはHTMLのように見えますが、JavaScriptです。constがheadingという新しい変数を作り、その変数の値がJSX式の結果となります。

JSXの仕組み

JSXは、ブラウザで実行される前に、通常のJavaScriptに変換されます。この変換は、トランスパイラと呼ばれるツールを使って行われます。JSXの最も一般的なトランスパイラはBabelです。

Babelは、JSXのコードを一連の関数呼び出しに変換します。これらの関数呼び出しは、JSXで書かれたHTMLのようなコードと同等になります。そして、ブラウザは、結果として得られたJavaScriptコードを実行することができます。

例えば、次のようなJSXコードです。

const element = <h1>Hello, world!</h1>;

これが、次のようなJavaScriptコードに変換されます。

const element = React.createElement("h1", null, "Hello, world!");

この変換により、開発者はJavaScriptの性能と柔軟性を生かしながら、慣れ親しんだ読みやすい構文でコードを書くことができます。

JSXとReact

JSXはReactに不可欠な要素であり、これによりコンポーネントのマークアップとロジックを1つのファイルに記述することができるようになります。

以下は、ReactコンポーネントのJSXコードの簡単な例です。

import React from 'react';

function Greet() {
  return <h1>Hello World!</h1>;
}

export default Greeting;

この例では、Greetという名前の関数コンポーネントがあり、h1要素を挨拶のメッセージとしてレンダリングしています。

Reactコンパイラは、このコードをブラウザで実行できる最適化されたJavaScriptコードに変換し、コンポーネントを画面上に表示できるようにします。

以下は、ReactコンパイラがGreetコンポーネントを変換した結果です。

import React from 'react'

function Greet() {
  return React.createElement("h1", {}, "Hello, World!")
}

このコードでは、JSXコードは、元のJSXコードと同じ構造とコンテンツを作成するReact.createElement に変換されています。

ReactがJSXコードをコンパイルする際に、上記のような変換が舞台裏で起こっています。これにより、ブラウザによる実行が可能になります。ただし、変換されたコードは、元のJSXコードよりも可読性が低くなる可能性があります。

Reactバージョン17では、新しいJSX変換機能が導入され、Reactパッケージの新しいエントリポイントから特別な関数を自動的にインポートすることで、ファイルの先頭でReactをインポートしなくてもJSXを使用できるようになりました。

// コンパイラが挿入(自分でインポートする必要なし)
import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}

JSXでJavaScriptの式を使う

JSXでは、JavaScriptの式をマークアップ内に直接埋め込んで、コンテンツを動的に生成することができます。これにより、JavaScriptコードを使用して、JSXコンポーネント内で値の計算、操作、および条件付きでコンテンツのレンダリングを行うことができます。

以下の例では、JSX内で2つのJavaScriptの式を使用しています。

import React from 'react';

const MyComponent = () => {
  const name = 'John';
  const age = 30;

  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>You are {age} years old.</p>
      <p>Next year, you will be {age + 1} years old.</p>
      {age >= 18 && <p>You are an adult.</p>}
    </div>
  );
};

export default MyComponent;

この例では、{name}{age}{age + 1}{age >= 18 && <p>You are an adult.</p>}のような JavaScriptの式を使用して、nameとageの変数の値に基づきコンテンツを動的にレンダリングしています。

JSXでCSSを使う

CSSは、インラインスタイル、個別のCSSファイル、CSS in JSライブラリなど、さまざまな方法でJSXコンポーネントに適用することができます。インラインスタイルは、JavaScriptオブジェクトを使用してJSXマークアップ内で直接定義され、外部CSSファイルまたはCSS in JSライブラリでは、コンポーネントの外部およびモジュールに基づいたスタイル設定が可能になります。

以下の例では、JavaScriptオブジェクトを使用して定義されたインラインスタイルを、JSXのstyle属性を使用して要素に適用しています。

import React from 'react';

const MyComponent = () => {
  const styles = {
    backgroundColor: 'blue',
    color: 'white',
    padding: '10px'
  };

  return (
    <div style={styles}>
      <h1>Hello, World!</h1>
      <p>This is a component with inline styles.</p>
    </div>
  );
};

export default MyComponent;

この例では、backgroundColorcolor、padding などのCSSプロパティをstylesオブジェクトのキーと値のペアとして設定し、その値をCSS値を表す文字列としています。

注)インラインスタイルには柔軟性と簡便性がありますが、より複雑なスタイルや大規模なアプリケーションでは、CSSクラスまたはCSS in JSライブラリを使用することが推奨されます。

重要なJSXのルール6選

JSXのコードを書くときには、妥当で読みやすいものにするために守るべきルールがあります。

1. 常に1つのルート要素を返す

JSXでは、常に1つのルート要素を返さなければなりません。つまり、JSXのコードはすべて、一番外側にある1つの要素に収めなければなりません。例えば、以下は有効なJSXです。

return (
  <div>
    <h1>Hello World!</h1>
    <p>This is my first React component.</p>
  </div>
)

しかし、以下は1つの要素ではなく2つの要素を返しているため、有効ではありません。

return (
  <h1>Hello World!</h1>
  <p>This is my first React component.</p>
)

これは、HTMLコードをJSXに変換する際に注意しなければならない点です。

2. classの代わりにclassNameを使う

HTMLでは、要素のCSSクラスを指定するために、class属性を使用します。しかし、JSXでは、代わりにclassName属性を使用する必要があります。例えば、以下のようになります。

// ○
<div className="my-class">This element has a CSS class.</div>

// X
<div class="my-class">This element has a CSS class.</div>

classの代わりにclassNameを使用することが重要です。これで命名の衝突を避けることができます。

3. JavaScriptの式には中括弧を使用する

JSXコードの中にJavaScriptの式を含める必要がある場合、中括弧{}で囲む必要があります。これは、動的なデータの表示から、コンポーネントの条件付きレンダリングまで、あらゆる用途に使用できます。以下はその例です。

// ○
<div>{myVariable}</div>

// X
<div>myVariable</div>

中括弧の中では、次のような計算を実行することができます。

<p>The total cost is {25*10}</p>

また、中括弧の中では、三項演算子を使って条件文を設定することもできます。

<h1>{(x) < 15 ? "Welcome" : "Goodbye"}</h1>

以下に、Reactコンポーネントを使ったより良い例を紹介します。

function Greeting() {
  const isLoggedIn = true;

  return (
    <div>
      {isLoggedIn ? (
        <h1>Welcome back!</h1>
      ) : (
        <h1>Please log in.</h1>
      )}
    </div>
  );
}

この例では、Greetingコンポーネントを定義しています。このコンポーネントは、三項演算子を使用して、isLoggedInの値に基づいて条件付きで挨拶をレンダリングします。isLoggedIntrueの場合、コンポーネントはテキスト”Welcome back!”を含むh1 要素をレンダリングします。isLoggedInfalseの場合、コンポーネントは”Please log in.”というテキストを含むh1要素をレンダリングします。

4. ほとんどのものにcamelCaseを使用する

JSXでは、属性、イベントハンドラ、変数名など、ほとんどのものにcamelCaseを使用します。この規則は、JavaScriptの命名規則と一致しており、可読性を維持するのに役立ちます。

例えば、onclickの代わりにonClickを、classの代わりにclassNameを使用します。

// ○
<button onClick={handleClick} className="btn">Click me!</button>

// X
<button onclick={handle_click} class="btn">Click me!</button>

5. タグを常に閉じる

JSXでは、たとえタグに中身がなくても、常に閉じる必要があります。例えば、以下のようになります。

// ○
<div></div>

// X
<div/>

6. 空の要素はタグ単体で完結

本質的に中身を持たない要素であれば、開始/終了タグの代わりにタグ単体で完結することができます。例えば、以下のようになります。

// ○
<img src="my-image.jpg" alt="My Image"/>

// X
<img src="my-image.jpg" alt="My Image"></img>

なぜJSXがウェブ開発に重要なのか

JSXがウェブ開発にとって重要なのは、次のような理由からです。

  1. 直感的でなじみやすい方法でユーザーインターフェースを構築できる。
  1. DOMを直接操作する代わりに、JSXを使って、HTMLを書くのと同じような方法でユーザーインターフェースの構造を記述することができる。
  1. 効率的で柔軟な開発が可能になる。JSXはJavaScriptなので、開発者はJavaScriptのあらゆる機能を活用し、より複雑でダイナミックなユーザーインターフェースを作ることが可能。
  1. 現代のウェブ開発では、ユーザーインターフェースを構築する上で人気の選択肢であるReactライブラリの重要な構成要素。Reactを使いたいなら、JSXを学ぶ必要がある。

まとめ

JSXはJavaScriptの構文拡張で、JavaScriptファイル内にHTMLのようなマークアップを記述できるようになります。これにより、ウェブアプリケーションの動的でインタラクティブなユーザーインターフェースの作成が容易になります。

JSXを使用する際に従うべきいくつかのルールをご紹介しました。これに従うことで、JavaScriptの命名規則に沿った、クリーンで読みやすく、保守性の高いコードを書くことができます。