React 17 で改良された JSX Transform はどのようなものか

3 min読了の目安(約2700字TECH技術記事
Likes11

JSX Transform は JSX がブラウザでそのまま実行できないため、Babel や TypeScript を利用し、JSX を JavaScript に変換するもので、React 17 で新しくなり改善された点を紹介していきます。

新しい JSX Transform で何が変わるのか

JSX で毎回 React をインポートしなくてよくなります。

// この import が不要になります
import React from 'react'

そもそも何故 React の import が必要なのか

たとえば下記のようなコードでどこにも React を使っていないの import せず実行した場合、 ReferenceError React is not defined といったエラーが表示されます。

import React from 'react' // この import は不要なのでは?

const Foo = () => {
  return <h1>Hello World</h1>
}

このエラーの原因はトランスパイル後のコードに原因があって、実際に実行時される JavaScript のコードを見る必要があります。

従来の JSX Transform で React を import しなかった場合

import を削除してトランスパイルしてみます。

const Foo = () => {
  return <h1>Hello World</h1>
}

トランスパイル後のコードをみると React.createElement() が呼ばれているのがわかります。
さきほどのエラーで React が存在しないといわれたのはこのためです。

"use strict";

var Foo = function Foo() {
  return /*#__PURE__*/React.createElement("h1", null, "Hello World");
};

従来の JSX Transform で React を import した場合

次の例では React を import してトランスパイルします。

import React from 'react'

const Foo = () => {
  return <h1>Hello World</h1>
}

require された React が使用されているためエラーが発生せず実行できます。
従来の JSX Transform ではこのトランスパイル後のコードを意識して React を import する必要がありました。

"use strict";

var _react = _interopRequireDefault(require("react"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

var Foo = function Foo() {
  return /*#__PURE__*/_react["default"].createElement("h1", null, "Hello World");
};

新しい JSX Transform の場合

const Foo = () => {
  return <h1>Hello World</h1>
}

React を import しなくても react/jsx-runtime が読み込まれます。

import {jsx as _jsx} from 'react/jsx-runtime';

var Foo = function Foo() {
  return _jsx('h1', { children: 'Hello world' });
}

対応状況

React 17 のほか React 16.x、React 15.x、React 0.14.x へのバックポートも予定されており、
主要な環境だと下記のバージョンから利用可能です。

  • Create React App: v4.0 ( βテスト中 ) 以降
  • Next.js: v9.5.3 以降
  • Gatsbt: v2.24.5 以降

既存のコードへの対応

React を import する必要がなくなったため不要な import を削除するツールが存在します。

npx react-codemod update-react-imports

このツールは不要な import だけを削除してくれて、React.useState() のように使用している箇所も適切に分割 import に置き換えます。

React が使われていないパターン

不要な import が含まれるコードを変換した例を紹介します。

import React from 'react'

const Foo = () => {
  return <h1>Hello World</h1>
}

変換後のコードからは import が削除されました。

const Foo = () => {
  return <h1>Hello World</h1>
}

React が使われているパターン

つぎに React.useState() が使われているコードを変換した例を紹介します。

import React from 'react'

const Foo = () => {
  const [text, setText] = React.useState('Hello World')
  return <h1>{text}</h1>
}

useState のみが分割 import され、4 行目のコードも置き換えられました。

import { useState } from 'react'

const Foo = () => {
  const [text, setText] = useState('Hello World')
  return <h1>{text}</h1>;
}