React原理浅析(二):使用JSX创建元素对象

209 阅读2分钟

原文链接:github.com/chinanf-boy…

从上一节html DOM转换为Element元素对象可以看出,将DOM结构手动转换为元素对象是比较繁琐的,所以需要提供一种方式来简化元素对象的创建,这种方式就是JSX

JSX:简化元素对象书写

JSX提供了一些语法糖,来替代手动创建Element对象,我们可以这么书写以替代上一节的DOM树描述:

const element = (
  <div id="container">
    <input value="foo" type="text" />
    <a href="/bar">bar</a>
    <span onClick={e => alert("Hi")}>click me</span>
  </div>
);

对应的Element对象为:

const element = {
  type: "div",
  props: {
    id: "container",
    children: [
      { type: "input", props: { value: "foo", type: "text" } },
      {
        type: "a",
        props: {
          href: "/bar",
          children: [{ type: "TEXT ELEMENT", props: { nodeValue: "bar" } }]
        }
      },
      {
        type: "span",
        props: {
          onClick: e => alert("Hi"),
          children: [{ type: "TEXT ELEMENT", props: { nodeValue: "click me" } }]
        }
      }
    ]
  }
};

babel-loader:将JSX转换为有效的JS

JSX并不是有效的javascript,为了使浏览器能理解,需要将JSX代码由预处理转化为有效的JS,通常使用babel-loaderJSX转换为JS。 babel-loader会将上述JSX代码转换为一个递归使用createElement函数的对象:

const element = createElement(
  "div",
  { id: "container" },
  createElement("input", { value: "foo", type: "text" }),
  createElement(
    "a",
    { href: "/bar" },
    "bar"
  ),
  createElement(
    "span",
    { onClick: e => alert("Hi") },
    "click me"
  )
);

createElement函数:将JSX转换为Element对象

上面描述了babel-loader会将JSX转换为上述形式的JS,递归使用了createElement函数,所以需要支持将JSX转换为ElementcreateElement函数。

  • 入参:type(元素的html标签类型),props(元素的属性及子元素)
  • 出参:Eelemnt对象

createElement需要创建一个props对象,将其分配给第二个参数中的所有值,将该children属性设置为第二个参数后面的所有参数,然后返回一个Element对象({ type, props })。

function createElement(type, config, ...args) {
  const props = Object.assign({}, config);// 合并
  const hasChildren = args.length > 0; // 是否有孩子
  props.children = hasChildren ? [].concat(...args) : [];
  return { type, props }; // Didact元素的数据结构-类型{type}与属性{props}
}

总结

这两节我们介绍了3个概念之间的关系:JSXelement和html DOM,以及两个函数:createElement()render(),它们之间的关系如下图: