React原理之-jsx

332 阅读2分钟

1.什么是 jsx

jsx 是 js 代码,通过编译转换成虚拟 dom 节点。

  • JSX 是一个JavaScript的语法扩展,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式

react17 版本以前的转义,

注意:需要在文件头引入 react import React from 'react'

2. classic模式和automatic模式生成的结构对比

a) classic模式转换的jsx

const babel = require("@babel/core");
const sourceCode = `
<h1>
  hello<span style={{ color: 'red' }}>world</span>
</h1>
`;
const result = babel.transform(sourceCode, {
  plugins: [["@babel/plugin-transform-react-jsx", { runtime: "classic" }]],
});
// 生成的代码
React.createElement(
  "h1",
  null,
  "hello",
  React.createElement(
    "span",
    {
      style: {
        color: "red",
      },
    },
    "world"
  )
);

b)automatic模式转换的jsx

react 17 以后的转义, 转换后不需要在手动引入 react,运行时会加载runtime文件

const babel = require("@babel/core");
const sourceCode = `
<h1>
  hello<span style={{ color: 'red' }}>world</span>
</h1>
`;
const result = babel.transform(sourceCode, {
  plugins: [["@babel/plugin-transform-react-jsx", { runtime: "automatic" }]],
});
// automatic模式生成的代码,是用jsx方法来处理了,最终还是调用ReactElement生成虚拟dom
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";

/*#__PURE__*/
_jsxs("h1", {
  children: [
    "hello",
    /*#__PURE__*/ _jsx("span", {
      style: {
        color: "red",
      },
      children: "world",
    }),
  ],
});

// jsx和jsxs对应的方法,最终都是调用jsxDEV方法去做一些参数校验和props处理,然后创建react元素,虚拟dom
var jsx = jsxWithValidationDynamic; // we may want to special case jsxs internally to take advantage of static children.
// for now we can ship identical prod functions

var jsxs = jsxWithValidationStatic;

function jsxDEV(type, config, maybeKey, source, self) {
  {
    var propName; // Reserved names are extracted

    var props = {};
    var key = null;
    var ref = null;

    if (maybeKey !== undefined) {
      {
        checkKeyStringCoercion(maybeKey);
      }
      key = "" + maybeKey;
    }
    if (hasValidKey(config)) {
      {
        checkKeyStringCoercion(config.key);
      }
      key = "" + config.key;
    }
    if (hasValidRef(config)) {
      ref = config.ref;
      warnIfStringRefCannotBeAutoConverted(config, self);
    } // Remaining properties are added to a new props object

    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    } // Resolve default props
    // 前面的都是做一些校验和处理props,这里去创建虚拟dom
    return ReactElement(
      type,
      key,
      ref,
      self,
      source,
      ReactCurrentOwner.current,
      props
    );
  }
}

// element就是虚拟dom,react node。
var ReactElement = function (type, key, ref, self, source, owner, props) {
  var element = {
    // This tag allows us to uniquely identify this as a React Element
    $$typeof: REACT_ELEMENT_TYPE,
    // Built-in properties that belong on the element
    type: type, //元素标签span,h1等
    key: key, //唯一标识
    ref: ref,
    props: props, //属性 children,style,id
    // Record the component responsible for creating this element.
    _owner: owner,
  };

  return element;
};

浏览器运行时加载 jsx-dev-runtime.js,提供 jsxDev 方法.

  • React17以前老版的转换函数中key 是放在config里的,第三个参数放children
  • React17之后新版的转换函数中key是在第三个参数中的,children是放在config里的 无论是新版还是旧版最终都会调用 ReactElement 最终返回虚拟 DOM

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2天,点击查看活动详情