jsx-in-depth

深入JSX

JSX是一个JavaScript语法的一个扩展,它看起来很像XML.你可以在React里使用JSX语法转换

为什么是JSX

你不一定要在React里使用JSX,你可以使用纯JS,但是,我们建议你使用JSX,因为它提供了简洁,熟悉的语法来定义带有属性的树结构

对于临时发开人员比如设计师来说,JSX更亲切.

XML有标签的打开和闭合.这在树结构较大的时候,比调用函数或对象字面量更容易阅读.

它并不改变JavaScript语法.

HTML标签和React组件

React既可以渲染HTML标签(字符串),也可以渲染React组件(类)

要渲染一个HTML标签,请在JSX中使用小写的标签名:

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的JSX约定: 通过使用大写和小写字母开头命名,来区分本地的组件和HTML标签.

Note: 由于JSX是JavaScript,所以,classfor这类标识符不建议被用于XML的属性名. 取而代之的是,React的DOM建议给DOM元素的属性命名为类似于 classNmae,htmlFor 这样的规则.

转换

React JSX 会把像XML一样的语法转换成原生JavaScript. XML元素,属性,子元素,都会变成参数,传递给 React.createElement.

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

注意,要使用 <Nav /> , 作用域里必须有 Nav 变量.

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")
);

当 displayName 属性未被定义的时候, JSX 会通过它赋值的变量名来推断 displayName

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

通过 Babel REPL 来体验JSX是如何变成纯JavaScript的. 还有 HTML to JSX converter 这个网站可以把HTML转换成JSX.

如果你想要使用JSX,Getting Started教程会展示如何设置编译.

Note: JSX表达式最终的结果总是一个ReactElement.实际执行的细节会有一些变化.有一种优化的方法,它可以把ReactElement作为一个对象字面量内联进去,从而避免 React.createElement 的验证代码.

命名空间的组件

如果你要创建一个有很多子元素的组件,比如form,你很可能会需要申明很多变量名.

// 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>
);

为了简化它,命名空间的组件可以使用一个组件以及它的属性来作为它的子组件.

var Form = MyFormComponent;

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

要实现这个功能,你只需要创建你的子组件作为父组件的属性就可以了.

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)
    )
  )
);

Note: 这个特性只在v0.11及以上被支持.

JavaScript 表达式

属性里的表达式

要在属性里使用JavaScript表达式,把表达式包在 {} 里,而不是 “” 里

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

属性值是一个布尔值

如果一个属性的值被省略了,JSX会认为它的默认值就是 true. 如果要让它的值为 false,就必须要传入表达式, 这在HTML form表单里很常见,比如 disabled required checked readonly 属性等…

// 下面这两种禁用按钮的方式在JSX里是等价的.
<input type="button" disabled />;
<input type="button" disabled={true} />;

// 下面这两种不禁用按钮的方式在JSX里是等价的.
<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>
);

Note: JSX和HTML相似,但不完全相同.查看 JSX gotchas ,里面列出了一些常见的坑.

查看原文