React 17 で改良された JSX Transform はどのようなものか
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