React jsx的编译原理分析

4,993 阅读2分钟
前言

使用react的朋友对jsx的语法相当熟悉,JavaScript和html混合开发,灵活快速,DOM结构一目了然,经过babel处理在渲染到页面上,下面我们来看一下react如何处理jsx文件

下面看个demo,观察jsx的处理逻辑

先安装插件

yarn add webpack webpack-cli 
yarn add babel-loader 
yarn add @babel/plugin-transform-react-jsx
yarn add @babel/preset-react @babel/preset-env

简单配置一个webpack.config.js 解析 jsx

var path = require("path");
module.exports = {
  mode"development",
  entry"./demo1.jsx",
  devtool"source-map",
  output: {
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test/.jsx$/,
        use: {
          loader"babel-loader",
          options: {
            presets: ["@babel/preset-env"],
            plugins: ["@babel/plugin-transform-react-jsx"]
          }
        }
      }
    ]
  }
};

再来一段demo1.jsx

const name = "world";
<h1 title='title' ref='title'>
  hello, {name}
</h1>;

我们来看一下 webpack打包之后的文件内容

/***/ (function(moduleexports) {

var name = "world";

/*#__PURE__*/
React.createElement("h1", {
  title"title",
  ref"title"
}, "hello, ", name);

/***/ })

可以看到babel 解析成了React.createElement,官网上React.createElement的说明

React.createElement( type, [props], [...children]):根据指定的第一个参数创建一个React元素

第一个参数是必填,传入的是HTML标签名称,eg: ul, li

第二个参数是选填,表示的是属性,eg: className

第三个参数是选填, 子节点,eg: 要显示的文本内容,

React.createElement源码地址

 github.com/facebook/re…

const hasOwnProperty = Object.prototype.hasOwnProperty;

const RESERVED_PROPS = {
  keytrue,
  reftrue,
  __selftrue,
  __sourcetrue,
};

可以看到定义的属性ref,key会直接挂在生成元素上,而其他属性挂在props上,子元素可以是一个或者多个,都会被挂在props.children上,demo1的编译生成的"hello, ", name就是多个文本节点,最终生成的虚拟dom是这样子的

图片

jsx 组件大小写问题

组件名首字母一定要大写,如果bable转化时 发现当前标签的首字母为大写 则表示当前的标签是一个函数名称 否则当前标签为一个字符串 看个例子

const Comp = () => <h1>hello, world</h1>;
const App = () => {
  return <Comp />;
};

最终babel解析成

/*!*******************!*\
  !*** ./demo2.jsx ***!
  *******************/
/*! no static exports found */
/***/ (function(moduleexports) {

var Comp = function Comp() {
  /*#__PURE__*/
  return React.createElement("h1"null"hello, world");
};
/*#__PURE__*/
var App = function App() {
  //返回React组件类型元素
  return React.createElement(Compnull); 
};

/***/ })

/******/ });

若使用小写则会编译成

/*!*******************!*\
  !*** ./demo2.jsx ***!
  *******************/
/*! no static exports found */
/***/ (function(moduleexports) {
/*#__PURE__*/
var comp = function comp() {
  return React.createElement("h1"null"hello, world");
};

var App = function App() {
//返回字符串元素
/*#__PURE__*/
  return React.createElement("comp"null);
};

/***/ })

html 无法正常渲染

jsx文件不支持在花括号{}写表达式,原因大家大概知道为什么了吧

例如 { var a = 1; },babel会把var a=1;解析成子元素,肯定不对了,所以我们写jsx的时候要注意符合子元素定义