0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JSXについて改めて理解する

Posted at

はじめに

ReactのJSXについて、なんとなく使っている感があったので改めて整理してみました。

JSXってなんなの?

ReactのcreateElementをhtmlライクにかけるようにするものです。
JSXはBabelによって最終的にcreateElementに変換されるようです。
babel-plugin-transform-react-jsxで変換を行なっていそうです。

    // Builds JSX into:
    // Production: React.createElement(type, arguments, children)
    // Development: React.createElement(type, arguments, children, source, self)
    function buildCreateElementCall(
      path: NodePath<JSXElement>,
      file: PluginPass,
    ) {
      const openingPath = path.get("openingElement");

      return call(file, "createElement", [
        getTag(openingPath),
        buildCreateElementOpeningElementAttributes(
          file,
          path,
          openingPath.get("attributes"),
        ),
        // @ts-expect-error JSXSpreadChild has been transformed in convertAttributeValue
        ...t.react.buildChildren(path.node),
      ]);
    }

このbabelプラグインではJSXFragmentJSXElementJSXAttributeについて変換を行なっています。

JSXFragment/JSXElement

JSXFragmentは<Fragment>(<>...</>)の構文で使用されるものです。
JSXElementは<div>のようなhtml風のelementです。
変換の中は似たような動きをしているのでいっぺんに紹介します。

        JSXFragment: {
          exit(path, file) {
            let callExpr;
            if (get(file, "runtime") === "classic") {
              callExpr = buildCreateElementFragmentCall(path, file);
            } else {
              callExpr = buildJSXFragmentCall(path, file);
            }

            path.replaceWith(t.inherits(callExpr, path.node));
          },
        },
        JSXElement: {
          exit(path, file) {
            let callExpr;
            if (
              get(file, "runtime") === "classic" ||
              shouldUseCreateElement(path)
            ) {
              callExpr = buildCreateElementCall(path, file);
            } else {
              callExpr = buildJSXElementCall(path, file);
            }

            path.replaceWith(t.inherits(callExpr, path.node));
          },
        },

runtimeがclassicかautomaticかで変わるようです。デフォルトはautomaticのようです。
classicの場合、JSXで記述されたコードは直接React.createElementに変換されます。
automaticの場合、JSXで記述されたコードは_jsx_jsxsに変換されます。
React.createElementに変換されるのと、_jsxに変換される時の挙動の違いとして、_jsxはJSXの記載時にimport React from 'react';の記述が不要になります。詳しくはは新しい JSX トランスフォームに載っています。

buildJSXFragmentCallやbuildJSXElementCallの延長で小要素を取得して_jsxに置き換えをしています。

JSXAttribute

JSXAttributeはJSXで記述した際の属性を示しています。<a href={linkTarget()}>link</a>とかでいうとhref={linkTarget()}がattributeです。

        JSXAttribute(path) {
          if (t.isJSXElement(path.node.value)) {
            path.node.value = t.jsxExpressionContainer(path.node.value);
          }
        },

JSXAttributeのnodeがJSXElementの場合、jsxExpressionContainerでvalidationをかけて、結果をnodeに格納しているようです。
NodeTypeがExpressionかJSXEmptyExpressionであればvalidationがpassしそうです。
ExpressionはJavascriptの式であれば基本的にExpressionに当たるようです。JSXEmptyExpressionはJSXの中括弧 {} の間に何もない場合に生成されるようです。
以下のようなコードの{ }がそれに当たります。

<>
 { }
</>

結果、JSXAttributeはajavascriptの式か、空の式であるかどうかをチェックして、問題がなければそのまま値を格納するような動きをしていそうです。

おわりに

ここまでで一通りJSXの変換の断片を見てきました。
JSXはBabelによってJSXFragment/JSXElement/JSXAttributeなどに分類され、ツリー状のASTとして表現されます。
JSXFragment/JSXElementの場合は_jsx(その先はcreateElement)または、createElementに変換され、JSXAttributeはvalidationのみをされていることがわかりました。
また、runtimeをautomaticに設定することで、直接createElementに変換されず、_jsxに変換されるため、import React from 'react';を記述することなくJSXの構文で記述できることがわかりました。

次はcreateElementについて読んでみていきたいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?