まくろぐ
更新: / 作成:

React アプリケーションでは、コンポーネントの UI を JSX 構文を用いて記述します。 下記は、JSX コードを記述するときのポイントのまとめです。 通常の JavaScript コードとは異なる記述方法が必要になるため慣れが必要ですが、ここに挙げたポイントをおさえておけば大体対応できます。

JSX の最上位要素はひとつ

JSX 要素を作成するとき、トップレベルの要素は 1 つだけにする必要があります。 次のコードでは、トップレベルに 2 つの p 要素が並んでいるのでエラーになります。

ダメな例
const MyComponent: React.FC = () => {
  return (
    <p>Hello</p>
    <p>World</p>
  )
}

これを解決するには、例えば次のようにルート要素として div を配置します。

return (
  <div>
    <p>Hello</p>
    <p>World</p>
  </div>
)

もちろん、これはこれで動作するのですが、ルートに余計な div 要素が作られてしまうのを防ぎたいときは、次のように <>...</> で囲います(これは <React.Fragment> の省略記法です)。

return (
  <>
    <p>Hello</p>
    <p>World</p>
  </>
)

条件を満たすときのみ出力する

次のコードは、n > 0 を満たしたときに、後半の p 要素を表示します。

return <>
  {n > 0 && <p>条件を満たしたよ</p>}
</>

JSX コードの中では、iffor といった値を返さない文 (statement) を記述することができません。 なので、出力を条件分岐させたいときは、この例のように、&&|| のような演算子を駆使する必要があります。

JSX の {} 内に記述した式の評価結果が undefinednulltruefalse のいずれかになった場合、{} 全体は 何も出力しない ことを表します。 true の場合に何も表示されないのは直感的ではないと思うかもしれませんが、画面上に true と表示されても困るし、まぁそんなものだと受け入れるしかないですね。 上記コードの例でいうと、n > 0 の部分が「偽」になった瞬間に {} 全体が false として評価されるため、結果的に何も出力されないということになります。

if-else 出力

ある条件を満たしたときは A、満たさなかったときは B、と表示分けしたいときは、JavaScript の 三項演算子(?: を使います。 次のコードは、n が偶数のときに Even、奇数のときに Odd と出力します。

{n % 2 == 0 ? 'Even' : 'Odd'}

オブジェクトのあるプロパティが未設定 (undefined) のときに代替値を表示したいときは、ES2020 の Nullish Coalescing (??) を使うとシンプルに記述できます。 次の例では、movie オブジェクトの genre プロパティが設定されているときはその値を表示し、設定されていないときは 不明 と表示します。

{movie.genre ?? '不明'}

配列要素のループ出力

配列要素を forEach 風に繰り返し出力するには、map メソッドを使用します。 初めて見るとウッとなりますが、React/JSX の世界ではこの書き方は一般教養。 慣れるしかありません。

const foods = [
  { id: 1, name: 'apples' },
  { id: 2, name: 'bananas' },
  { id: 3, name: 'lemons' },
]

const FoodList: React.FC = () => {
  return (
    <ul>
      {foods.map((f) => (
        <li key={f.id}>I like {f.name}</li>
      ))}
    </ul>
  )
}

このように要素を繰り返し出力する場合は、React が効率的な差分出力を行えるように、各要素に一意な key プロパティ値を指定しなければいけないことに注意してください(参考: リストと key)。 これを忘れると、Each child in a list should have a unique "key" prop. といった警告が出ます。

辞書要素のループ出力

辞書(ディクショナリ)要素を繰り返し出力する場合は、Object.keys() でキーの配列を取り出し、それを map メソッドで処理します。

const myDict = {
  key1: 'value1',
  key2: 'value2',
  key3: 'value3',
}

function MyComponent() {
  return (
    <ul>
      {Object.keys(myDict).map((key) => (
        <li key={key}>{`${key}: ${myDict[key]}`}</li>
      ))}
    </ul>
  )
}

キー順にソートして出力したいときは、Object.key() で取り出したキー配列に対して sort() をかけます。

{Object.keys(myDict).sort().map((key) => ( /* ... */ ))}

n 回のループ出力

ちょっとハック的ですが、n 回の繰り返しは次のように記述できます。

{[...Array(3)].map((_, i) => (
  <p key={i}>{i}: Hello</p>
))}

[...Array(3)] という部分で、[undefined, undefined, undefined] というサイズ 3 の配列を作っておいて、各要素を map でループ処理してます。

コメントを記述する

JSX コードの中では、JavaScript と同様のコメント記法が使えます。

<>
  <div>
    {
      // 一行コメント
      n > 0 && <p>Hello</p>
    }
  </div>
  <div>
    {/*
      複数行にわたるコメントは、
      こんな感じで記述できます。
    */}
  </div>
</>

ユーザーコンポーネント名は大文字で始める

JSX コード内で使うユーザー定義コンポーネントの名前は、大文字で始めなければいけません。 小文字で始まる名前 (pdiv)は、組み込みのコンポーネントとして予約されているので使えません。 なお、JSX 組み込みのコンポーネントは JSX.IntrinsicElements として定義されており、200 近くのコンポーネントが定義されています。

関連記事

まくろぐ
サイトマップまくへのメッセージ