从本质上讲,JSX只是为React.createElement(component, props, ...children) 函数提供的语法糖, 即本质上还是调用的React.createElement(component, props, ...children)方法。例如JSX代码:
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
编译为:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
)
特殊情况:如果不存在子节点,可以使用自闭合(self-closing)格式的标签。例如:
<div className="sidebar" />
可以编译为:
React.createElement(
'div',
{className : 'sidebar'},
null
)
一. 指定React元素类型
一个JSX标签的开始决定了React元素的类型,首字母大写的标签指示JSX标签是一个React组件,这些标签会被编译成命名变量的直接引用。
1.1 React必须在作用域中
因为 JSX 被编译为 React.createElement 的调用,所以 React 库必须在你 JSX 代码的作用域中。
1.2 对JSX类型使用点语法
在 JSX 中,你也可以使用点语法引用一个 React 组件。如果你有一个单一模块(module) ,但却导出 (exports) 多个 React 组件时,这将会很方便。例如,如果 MyComponents.DatePicker 是一个组件,你可以直接在 JSX 中使用它:
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;
}
1.3 用户定义组件必须以大写字母开头
当一个元素类型以小写字母开头,他会认为这个锇元素是一个HTML标签,类似<div>
或者<span>
。所以一个组件必须以大写字母开头的方式命名。如果已经有一小写字母开头的组件,需要在使用时修改成大写字母开头。
1.4 在运行时选择类型
不能使用一个普通的表达式作为 React 元素类型。如果你想使用普通表达式来表示元素类型,首先你需要将其赋值给大写的变量。
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// 错误!JSX 类型不能是表达式
return <components[props.storyType] story={props.story} />;
}
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// 正确!JSX 类型可以是一个以大写字母开头的变量.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
二. JSX 中的 props(属性)
2.1 JavaScript 表达式作为props(属性)
可以传递任何一个用 {}
包裹的 JavaScript 表达式作为 props(属性)。
在JavaScript中,if
和for
不是表达式,因此不能直接在JSX中使用,但是可以放在附近的代码块中。
字符串字面量
可以传入一个字符串作为一个props(属性),当你传递一个字符串面量时,如果其值是为转移的HTML,那么一下两个JSX表达式是等效的:
<MyComponent message="<3" />
<MyComponent message={'<3'} />
2.2 props(属性)默认为“true”
如果没给prop(属性)传值,那么默认的就为true
。如下所示:
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
属性扩展
如果已经有一个object类型的props
,并且希望在JSX中传入,那么可以使用扩展操作符...
传入整个props对象。
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
注意:当在创建一个一般容器时,这样的方法非常有用。然而这可能会传递一些不相关的props(属性)给组件,而这些组件并不需要这些props。因此应当谨慎使用该语法。
三. JSX中的children
传递children时,JSX会删除每行开头和结尾的空格,并且也会删除空行。邻接标签的空行也会被移除,字符串之间的空格会被压缩成一个空格,因此下面四种传递字符串的渲染效果都是相同的:
<div>Hello World</div>
<div>
Hello World
</div>
<div>
Hello
World
</div>
<div>
Hello World
</div>
3.1 JSX Children
可以提供多个JSX元素作为children。这对显示嵌套组件非常有用。
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
注:React组件不能返回多个React元素,但是单个JSX表达式可以有多个子元素。
3.2 JavaScript 表达式作为 Children(子元素)
通过使用 {}
包裹,你可以将任何的 JavaScript 元素而作为 children(子元素) 传递。
对于渲染长度不定的JSX表达式非常有效,例如:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message)=><Item key={message} message={message}>)}
</ul>
);
}
3.3 Functions(函数) 作为 Children(子元素)
如果有自定义组件,props.children
的值可以是回调函数:
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return <div>{items}</div>;
}
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index} in the list</div>}
</Repeat>
);
}
3.3 Booleans,Null和Undefined被忽略
false
,null
,undefined
,和 true
都是有效的的 children(子元素) 。但是并不会被渲染,在有条件性渲染React元素时非常有用,如下所示:
<div>
{ showHeader && <Header /> }
<Content />
</div>
注意:需要注意的是
"falsy"值
,例如数值0,仍然会被React渲染,要修复这个问题,要确保&&
之前的表达式总是布尔值。
反过来,如果想在输出中渲染false
,null
,undefined
,和 true
,必须现将其转化为字符串:
<div>
My JavaScript variable is {String(myVariable)}.
</div>