深入理解` JSX`


是一个 javascript 语法的扩展, 看上去像 xml, 可以通过 React 对简单的 JSX 进行语义上的转换.

### 为什么需要它?

其实也并不是完全需要 React 和 JSX 绑在一起使用, 当然完全 js 都能够应付. 但是推荐使用 JSX, 因为它的语法更加类似一种树结构的定义. 用起来更加像设计人员在干活. `XML` 它有个优点就是有开始结束标签, 这样就能够很容易来阅读相对于函数调用或者是使用对象描述等.

### HTML 的标签和 React 的组件

`React` 可以渲染 HTML 的标签(字符串)或者 React 的组件(类).
JSX渲染一个 html 的 标签,通过使用小写的`标签名`就可以完成:

```
var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));

```

渲染一个React 的组件,可以通过声明一个变量, 然后大写开始:

```
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
ReactDOM.render(myElement, document.getElementById('example'));
```

React 通过大小写的约定来约束声明的是本地组件还是一个 HTML 的标签.

>由于 JSX 本身还是 javascript, 所以对于` class` 或者` for` 这样的关键字不推荐使用作用 xml 的属性名, React 的 DOM 组件推荐使用如 className 或者 htmlFor 这样的名字.

### 转换

要把类` XML` 结构的` JSX` 转换为原生的` javascript`, 其实具体的转换规则就是把 xml 的元素属性和其子元素一起作为参数传递给` React.createElement`.

```
var Nav;
// Input (JSX):
var app = <Nav color="blue" />;
// Output (JS):
var app = React.createElement(Nav, {color:"blue"});
```

这里注意, 我们现实声明了` Nav`, 为的就是能够使用`<Nav/>`这个 tag.
同时, JSX 允许通过使用 XML 的语法来声明子元素.


```
var Nav, Profile;
// Input (JSX):
var app = <Nav color="blue"><Profile>click</Profile></Nav>;
// Output (JS):
var app = React.createElement(
  Nav,
  {color:"blue"},
  React.createElement(Profile, null, "click")
);
```

在声明 React 的组件的时候,需要需要` displayName` 的属性, 当在编译的时候如果没有这个指, JSX 会去声明时的变量名:

```
// Input (JSX):
var Nav = React.createClass({ });
// Output (JS):
var Nav = React.createClass({displayName: "Nav", });

```

通过 [Babel REPL 我们可以试验 JSX 看他如何转换为原始的 javascript](https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&code=%2F%2F%20list%20matching%0Avar%20%5Ba%2C%20%2Cb%5D%20%3D%20%5B1%2C2%2C3%5D%3B%0Avar%20app%20%3D%20%3CNav%20color%3D%22blue%22%3E%3CProfile%3Eclick%3C%2FProfile%3E%3C%2FNav%3E%3B). 还有就是能够看看如何把 html 的标签转换为 JSX. 

这么说, 如果你直接在 console 里贴这样的代码就会报错:

```
var app = <Nav color="blue"><Profile>click</Profile></Nav>;
```
:arrow_down: :arrow_down: :arrow_down: 



![Kobito.pWSX0i.png](https://qiita-image-store.s3.amazonaws.com/0/56713/d2117b8f-0a4a-a1d8-d325-9131e181708c.png "Kobito.pWSX0i.png")


也就是 react 它这个包本身就包括了这个编译功能, 当在 js 里遇到这样类 xml 的写法是 string 时就按照 jsx 对待,直接翻译成原始的 js.


> 当然上面的解释可以对于很多人没有必要,可是我就是需要说明白了才能懂.


!!!!
>注意, 对于一切的 JSX 判断, react 都会把它解释成为 react 的 `ReactElement`对象, 实际实现的方式可能很多.一个优化的方式就是直接讲 reactelement 表述为一个对象,然后传给` React.createElement`.


###基于命名空间

如果要创建的一个组件包含了很多的子节点,例如一个表单, 就会说明很多变量. 

```
// Awkward block of variable declarations
var Form = MyFormComponent;
var FormRow = Form.Row;
var FormLabel = Form.Label;
var FormInput = Form.Input;

var App = (
  <Form>
    <FormRow>
      <FormLabel />
      <FormInput />
    </FormRow>
  </Form>
);

```

这个看上去就比较 shi 了,如果通过`命名空间`组件就能够变得优雅些:

```

var Form = MyFormComponent;

var App = (
  <Form>
    <Form.Row>
      <Form.Label />
      <Form.Input />
    </Form.Row>
  </Form>
);

```

怎么才能够做到呢? 需要给`主组件`声明创建一个所谓的`子组件`的属性.:+1: 

```
var MyFormComponent = React.createClass({ ... });

MyFormComponent.Row = React.createClass({ ... });
MyFormComponent.Label = React.createClass({ ... });
MyFormComponent.Input = React.createClass({ ... });
```

这样在编译的时候 JSX 会编译成这样子:

```
var App = (
  React.createElement(Form, null,
    React.createElement(Form.Row, null,
      React.createElement(Form.Label, null),
      React.createElement(Form.Input, null)
    )
  )
);
```

>注意: 从 v0.11才开始支持

###Javascript 的表达式

#### 属性表达式

在 JSX 中, 你可以对属性用表达式来书写, 通过使用`{}`来代替`""`:

```
// Input (JSX):
var person = <Person name={window.isLoggedIn ? window.name : ''} />;
// Output (JS):
var person = React.createElement(
  Person,
  {name: window.isLoggedIn ? window.name : ''}
);
```

#### 布尔属性

当你声明了一个属性单没有给它值, 那么就把它当` true` 来看.所以当需要` false` 的时候就需要显式给它一个 false 的值. 这个经常在写一些 html 标签的时候遇到.如` disabled`, `required` 等

```
// These two are equivalent in JSX for disabling a button
<input type="button" disabled />;
<input type="button" disabled={true} />;

// And these two are equivalent in JSX for not disabling a button
<input type="button" />;
<input type="button" disabled={false} />;

```

#### 子元素表达式

我们甚至可以用 javascript 的表达式来声明子元素:


```
// Input (JSX):
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
// Output (JS):
var content = React.createElement(
  Container,
  null,
  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
);

```

#### 注释

JSX 中很容易添加注释, 他们当然也是 js 的表达式了. 通常也是通过`{}`来表达:


```
var content = (
  <Nav>
    {/* child comment, put {} around */}
    <Person
      /* multi
         line
         comment */
      name={window.isLoggedIn ? window.name : ''} // end of line comment
    />
  </Nav>
);
```

> 有人说 JSX 也看上去像 HTML 了, 不过也是有区别的, 通过 [JSX gotchas](https://facebook.github.io/react/docs/jsx-gotchas.html)来看看他们的不同.