明白JSX

起首jsx绝不是一个新的言语,我以为他仅仅是js的超集,或许只是一种语法糖。底本FB是有本身的jsx-transform来担任jsx的剖析,不过如今已住手更新,jsx语法完整依靠babel举行剖析。

babel

babel在辨认jsx的时刻,会将标签直接作为AST的node,然后转化

class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {this.props.value}
      </button>
    );
  }
}

将被babel转化为

class Square extends React.Component {
  render() {
    return React.createElement(
      "button",
      { className: "square" },
      this.props.value
    );
  }
}

这里为了轻易和浏览对es6的转化,临时疏忽。

AST

照样针对上面的代码,来看一下babylon AST的剖析效果,只包括return部份
全部标签部份是JSXElement
个中会有三个部份openingElement,closingElement和children,属性则会成为openingElement的JSXAttribute

jsx在babel的定义

defineType("JSXElement", {
  builder: ["openingElement", "closingElement", "children", "selfClosing"],
  visitor: ["openingElement", "children", "closingElement"],
  aliases: ["JSX", "Immutable", "Expression"],
  fields: {
    openingElement: {
      validate: assertNodeType("JSXOpeningElement"),
    },
    closingElement: {
      optional: true,
      validate: assertNodeType("JSXClosingElement"),
    },
    children: {
      validate: chain(
        assertValueType("array"),
        assertEach(
          assertNodeType(
            "JSXText",
            "JSXExpressionContainer",
            "JSXSpreadChild",
            "JSXElement",
            "JSXFragment",
          ),
        ),
      ),
    },
  },
});

AST的jsx节点末了会被替换为createElement的情势,也就是说不管怎么用jsx,实在也就只是一种语法糖,与createElement的写法无异

e.g

为了更好的明白jsx,那我诠释一段近来看到的代码

methodsParamsList.map((ListSourceComponent, index) => {
       return <ListSourceComponent.component index={index + 1} />
})

中心也就是openingElement
<ListSourceComponent.component index={index + 1} />
在babel的眼里他做为Element有两个部份,名字和属性,属性不多说了。
ListSourceComponent.component会被认为是JSXMemberExpression,ListSourceComponent是JSXIdentifier的对象component则是属性
假如是
<ListSourceComponent index={index + 1} />
那末ListSourceComponent是JSXIdentifier的name

全部代码的效果也就是

 methodsParamsList.map((ListSourceComponent, index) => {
      return React.createElement(ListSourceComponent.component, { index: index + 1 });
    });

实在在转码的阶段是不是将JSXMemberExpression的name或许对象的首字母大写是不重要的,真的致使报错的也不过是在createElement中

createElement

createElement()

React.createElement(type, [props],[…children])

Create and return a new React element of the given type. The type argument can be either a tag name string (such as ‘div’ or ‘span’), or a React component type (a class or a function).
Code written with JSX will be converted to use React.createElement(). You will not typically invoke React.createElement() directly if you are using JSX. See React Without JSX to learn more.

reactComponent大写的缘由

在刚学react的时刻,先生就说过react component须要大写,react会把大写启齿的作为react的组件,不然则会使一般的html dom,比方div,span
起首是不是是在剖析ast的时刻就把大小写离开处理了,答案是不是定的,在定义openingElement的type的时刻完整没有对这个举行推断,不管是大写,小写均作为string,是element的type
然则在babel的效果里能够看到
React.createElement('div', ...)
React.createElement( Div, ...)
这两种效果带来的就是Div这个是一个字符串照样变量名,假如本身不慎写了个小写的component名,那末一个并非html标签的字符串必然会形成毛病
这里必需交叉一个JSX dot notation

JSX dot notation

这个和上面的例子相干就是dot notation在jsx中的剖析

methodsParamsList.map((ListSourceComponent, index) => {
       return <ListSourceComponent.component index={index + 1}/>
    })
methodsParamsList.map((listSourceComponent, index) => {
       return <listSourceComponent.component index={index + 1}/>
    })

上面两段代码都不会致使毛病,缘由就是在剖析JSXIdentifier的效果会是一组对象和属性,所以转码效果肯定不是字符串而是obj.pro

jsx的变形

上面说到了在构建ast的过程当中大小写并不举行辨别,而是在@babel/plugin-transform-react-jsx中举行变化。
关于上面的几个转码的效果的诠释都在下面的源码中

  const createIdentifierParser = (id: string) => () => {
    return id
      .split(".")
      .map(name => t.identifier(name))
      .reduce((object, property) => t.memberExpression(object, property));
  };

这里能够发明,react支撑dot notation,然则比方
<A['x'] />
就肯定会报错了,虽然看起来与
<A.x />
一样

    原文作者:求实亭下
    原文地址: https://segmentfault.com/a/1190000013870949
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞