🎃

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

2020/10/06に公開

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>;
};

Discussion