深入JSX
JSX 仅仅只是 React.createElement(component, props, ...children)
函数的语法糖。
如下 JSX 代码:
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
会编译为:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
)
用户定义的组件必须以大写字母开头
以小写字母开头的元素代表一个 HTML 内置组件,比如 <div>
或者 <span>
会生成相应的字符串 'div'
或者 'span'
传递给 React.createElement
(作为参数)。大写字母开头的元素则对应着在 JavaScript 引入或自定义的组件,如 <Foo />
会编译为 React.createElement(Foo)
。
我们建议使用大写字母开头命名自定义组件。
例子:
import React from 'react';
// 错误!组件应该以大写字母开头:
function hello(props) {
// 正确!这种 <div> 的使用是合法的,因为 div 是一个有效的 HTML 标签
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// 错误!React 会认为 <hello /> 是一个 HTML 标签,因为它没有以大写字母开头:
return <hello toWhat="World" />;
}
要解决这个问题,我们需要重命名 hello
为 Hello
,同时在 JSX 中使用 <Hello />
:
import React from 'react';
// 正确!组件需要以大写字母开头:
function Hello(props) {
// 正确! 这种 <div> 的使用是合法的,因为 div 是一个有效的 HTML 标签:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// 正确!React 知道 <Hello /> 是一个组件,因为它是大写字母开头的:
return <Hello toWhat="World" />;
}
JSX 中的 Props
JavaScript 表达式作为 Props
你可以把包裹在 {}
中的 JavaScript 表达式作为一个 prop 传递给 JSX 元素。例如,如下的 JSX:
<MyComponent foo={1 + 2 + 3 + 4} />
在 MyComponent
中,props.foo
的值等于 1 + 2 + 3 + 4
的执行结果 10
。
字符串字面量
你可以将字符串字面量赋值给 prop. 如下两个 JSX 表达式是等价的:
<MyComponent message="hello world" />
<MyComponent message={'hello world'} />
Props 默认值为 “True”
如果你没给 prop 赋值,它的默认值是 true
。以下两个 JSX 表达式是等价的:
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
通常,我们不建议不传递 value 给 prop,因为这可能与 ES6 对象简写 混淆,{foo}
是 {foo: foo}
的简写,而不是 {foo: true}
。
属性展开
如果你已经有了一个 props 对象,你可以使用展开运算符 ...
来在 JSX 中传递整个 props 对象。以下两个组件是等价的:
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;}
JSX 中的子元素
包含在开始和结束标签之间的 JSX 表达式内容将作为特定属性 props.children
传递给外层组件。有几种不同的方法来传递子元素:
字符串字面量
你可以将字符串放在开始和结束标签之间,此时 props.children
就只是该字符串。
<MyComponent>Hello world!</MyComponent>
这是一个合法的 JSX,MyComponent
中的 props.children
是一个简单的未转义字符串 "Hello world!"
。
JSX 会移除行首尾的空格以及空行。与标签相邻的空行均会被删除,文本字符串之间的新行会被压缩为一个空格
JSX 子元素
子元素允许由多个 JSX 元素组成。这对于嵌套组件非常有用:
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
你可以将不同类型的子元素混合在一起,因此你可以将字符串字面量与 JSX 子元素一起使用。
React 组件也能够返回存储在数组中的一组元素:
render() {
// 不需要用额外的元素包裹列表元素!
return [
// 不要忘记设置 key :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
JavaScript 表达式作为子元素
JavaScript 表达式可以被包裹在 {}
中作为子元素。例如,以下表达式是等价的:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
布尔类型、Null 以及 Undefined 将会忽略
false
, null
, undefined
, and true
是合法的子元素。但它们并不会被渲染。以下的 JSX 表达式渲染结果相同:
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
值得注意的是有一些 “falsy” 值 ,如数字 0
,仍然会被 React 渲染。例如,以下代码并不会像你预期那样工作,因为当 props.messages
是空数组时,0
仍然会被渲染:
<div>
{
props.messages.length && <MessageList messages={props.messages} />
}
</div>
要解决这个问题,确保 &&
之前的表达式总是布尔值:
<div>
{
props.messages.length > 0 && <MessageList messages={props.messages} />
}
</div>