見出し画像

React JSXの実現とwebpackなどの細かい調査

こんにちは。 Showcase Gig でエンジニアをしている、ryoです。

最近O:der Platformの開発でReactを使いながらいろいろ勉強をしました。 今日は、React入り口のJSXをもとに、簡単なコードからコード裏に潜んだdesign方針までを説明します。

syntactic sugar

simple code

先に簡単なReact component codeです:  App.tsx

import React from 'react';
export default function App(): JSX.Element {
 return (
   <div>syntactic sugar for typescript</div>
 );
}

上のコードはまったくReactを使っていないのに、なぜ最初Reactをimportする必要( import React from 'react' )があるかっていう疑問が初めてReactを書いた時自然に湧いてきました。

import文をコメントアウトしたら、エラーになります。

画像2

もともと、Web browserはjsしか識別できないから、先にwebpackなどでtsxをjsにtranspileしないといけません。 transpile後のコードを確認すると、赤枠通りtsxはjsにtranspileされていました。

画像3

tsxにある <div>syntactic sugar for typescript</div> はjsにtranspileされました。

react_1.default.createElement(\"div\", null, \"syntactic sugar for typescript\")); 

引き続き調査したら、 react_1.default はReactであると分かりました。 

var react_1 = __importDefault(__webpack_require__(/*! react */ \"./node_modules/react/index.js\")); 

まとめると次のようになります。

1. JSX(tsx)は React.createElement にtranspileされます。
2. JSXは React.createElement のSyntactic Sugarです。

jsの場合

前述のはすべてtsですが、jsだったら、エラーは少し違います。

画像1

参考になったlink

Introducing JSX
JSX is syntactic sugar

React 17以降

前述のsimple codeの場合は import React from 'react' がいらなくなります。 例えば:

function App(): JSX.Element {
 return <h1>Hello World</h1>;
}

Babelは下の形にtranspileします。

import {jsx as _jsx} from 'react/jsx-runtime';
function App() {
 return _jsx('h1', { children: 'Hello world' });
}

設計

IoC:

もともとfunction componentはfunctionとしても呼び出せます。例えば: <div>{App()}</div> 。だがそうすると、Reactが部品を一般のfunctionとして識別します。 この場合、Reactがfunctionのmetadataを何も知らなくて何もできなくなってしまいます。これは開発者のみが部品をコントロールするパターンになります。 

逆にJSX( React.createElement )として使われるなら、部品の情報はReactが全て把握でき、 Reactがいろいろできるようになります。例えば「部品のタイプが違ったら、Reactはpropsを比較せず、古い部品を入れ替える」といったことができます。 これはライブラリ(React)が部品をコントロールするパターンです。コントロールを一気に開発者からReactに逆転させました。

Dan Abramove氏の説明

inversion of control。日本語の翻訳がないので、一部訳してみます。 なぜ部品を直接に呼ばないのか ?  Form() より <Form /> の方が使われるのはなぜでしょうか ? 再帰的にfunctionを呼び出してReact elementの階層のみより、部品の詳細まで把握できた方が、Reactはもっと良くやってくれます。

// NG: ReactはLayoutとArticleの存在は知らない.
// 開発者はfunctionとして呼び出します。
ReactDOM.render(
 Layout({children: Article()}),
 domContainer
)

// OK: ReactはLayoutとArticleは把握します。
// Reactは部品を呼び出します。
ReactDOM.render(
 <Layout><Article></Article></Layout>,
 domContainer
)

これはIoCの良くあった例です。部品の呼び出しをReactに預けたら、複数のおもしろい特性を得られます。

部品はfunctionのみではない

Reactは部品の機能を増強できます。例えば:部品のidエンティティと紐づいているローカルstate。 良いruntimeは手元にある課題と一致する基本的な抽象を与えてくれます。 Reactはui treesのレンダリングとinteractionへの反応向けですので、直接部品を呼ぶと、これらのフィーチャーは自ら実装しないといけません。

部品のタイプはreconciliationに使われます

部品の呼び出しをReactに預けたら、部品treeの構造もReactに知らせることができます。 例えば、 <Feed> のレンダリングから <Profile> のレンダリングに切り替えたら、Reactは <Feed> 部品内のものを再利用しないで、すぐ <Profile> をレンダリングします。 コンセプト上に違ったviewをレンダリングするのにこれは良い案です。

Reactはreconciliationを後回しできます

Reactが部品の呼び出しをコントロールできたら、いろいろおもしろいことはできます。 例えば:部品の呼び出しの間に、ブラウザーにほかのことをやらせますので、大きな部品treeのre-renderingはmain threadをブロックしません。 この機能を成し遂げるのにReactの大部分を再度実現しない限りは難しいです。

もっと良くdebugできます

部品はライブラリが識別できるfirst-class citizensになったら、開発者に使われるrich developer toolsは作られます。

まとめ

JSXはapp開発者が使いやすくするために導入されたものです。しかし、Web browserが識別できないので、ほかのツール(webpackなど)で識別できるコードに書き換えられていたのです。

最後に

React経験はまだまだ浅いですが、今後もReactに関するものをシェアしていきたいです!

Showcase Gigで急成長するプロダクトを一緒に作る仲間を募集しています!





この記事が気に入ったらサポートをしてみませんか?