深入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,所以,class和for这类标识符不建议被用于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 ,里面列出了一些常见的坑.