本质上来讲,JSX 只是为 React.createElement(component, props, ...children)
方法提供的语法糖。比如下面的代码:
Click Me
编译为:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
)
如果没有子代,你还可以使用自闭合标签,比如:
编译为:
React.createElement(
'div',
{className: 'sidebar'},
null
)
如果你想彻底验证 JSX 是如何转换为 JavaScript 的,你可以尝试 在线 Babel 编译器.
指定 React 元素类型
JSX 的标签的第一部分决定了 React 元素的类型。
首字母大写的类型表示 JSX 标签引用到一个 React 组件。这些标签将会被编译为直接引用同名变量,所以如果你使用了
JSX 表达式,则 Foo
必须在作用域中。
React 必须在作用域中
由于 JSX 编译成React.createElement
方法的调用,所以在你的 JSX 代码中,React
库必须也始终在作用域中。
比如,下面两个导入都是必须的,尽管 React
和 CustomButton
都没有在代码中被直接调用。
import React from 'react';
import CustomButton from './CustomButton';
function WarningButton() {
// return React.createElement(CustomButton, {color: 'red'}, null);
return ;
}
如果你没有使用JavaScript 打捆机,而是从标签加载React,它已经在作用域中,以
React
全局变量的形式。
点表示法用于JSX类型
你还可以使用 JSX 中的点表示法来引用 React 组件。你可以方便地从一个模块中导出许多 React 组件。例如,有一个名为 MyComponents.DatePicker
的组件,你可以直接在 JSX 中使用它:
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return Imagine a {props.color} datepicker here.;
}
}
function BlueDatePicker() {
return ;
}
用户定义组件必须首字母大写
当元素类型以小写字母开头时,它表示一个内置的组件,如 我们建议用大写开头命名组件。如果你的组件以小写字母开头,请在 JSX 中使用之前其赋值给大写开头的变量。 例如,下面的代码将无法按预期运行: 为了解决这个问题,我们将 你不能使用一个通用的表达式来作为 React 元素的标签。如果你的确想使用一个通用的表达式来确定 React 元素的类型,请先将其赋值给大写开头的变量。这种情况一般发生于当你想基于属性值渲染不同的组件时: 要解决这个问题,我们需要先将类型赋值给大写开头的变量。 在 JSX 中有几种不同的方式来指定属性。 你可以传递JavaScript 表达式作为一个属性,再用大括号 对于 你可以在相关部分中了解有关 条件渲染 和 循环 的更多信息。 你可以将字符串常量作为属性值传递。下面这两个 JSX 表达式是等价的: 当传递一个字符串常量时,该值为HTML非转义的,所以下面两个 JSX 表达式是相同的: 这种行为通常是无意义的,提到它只是为了完整性。 如果你没有给属性传值,它默认为 一般情况下,我们不建议这样使用,因为它会与 ES6 对象简洁表示法 混淆。比如 如果你已经有了个 你也可以选取特定属性对象来被组件使用,同时使用“展开(spread)”操作符将其他属性传递下去。 在上述例子中, 展开属性非常有用。但是他们也容易传递不必要的属性给组件,而组件并不需要这些多余属性。或者传递无效的HTML属性给DOM。我们建议你谨慎使用此语法。 在既包含开始标签又包含结束标签的 JSX 表达式中,这两个标签之间的内容被传递为专门的属性: 你可以在开始和结束标签之间放入一个字符串,则 这是有效的 JSX,并且 JSX 会移除空行和开始与结尾处的空格。标签邻近的新行也会被移除,字符串常量内部的换行会被压缩成一个空格,所以下面这些都等价: 你可以提供更多个 JSX 元素作为子代,这对于嵌套显示组件非常有用: 你可以混合不同类型的子代,同时使用字符串字面量和 JSX子代,这是 JSX 类似 HTML 的另一种形式,这在 JSX 和 HTML 中都是有效的: React 组件也可以返回包含多个元素的一个数组: 你可以将任何 这对于渲染任意长度的 JSX 表达式的列表很有用。例如,下面将会渲染一个 HTML 列表: JavaScript 表达式可以与其他类型的子代混合使用。这通常对于字符串模板非常有用: 通常情况下,插入 JSX 中的 JavaScript 表达式将被认作字符串、React 元素或这些的一个列表。然而, 传递给自定义组件的子代可以是任何东西,只要该组件在 React 渲染前将其转换成 React 能够理解的东西。这个用法并不常见,但当你想扩展 JSX 时可以使用。 这在根据条件来确定是否渲染React元素时非常有用。以下的JSX只会在 一个告诫是JavaScript中的一些 "falsy" 值(比如数字 要解决这个问题,请确保 相反,如果你想让类似 ,将导致字符串
'div'
或 'span'
传递给 React.createElement
。 以大写字母开头的类型,如
编译为 React.createElement(Foo)
,并且它正对应于你在 JavaScript 文件中定义或导入的组件。
import React from 'react';
// 错误!组件名应该首字母大写:
function hello(props) {
// 正确!div 是有效的 HTML 标签:
return
hello
重命名为 Hello
,然后使用
引用:import React from 'react';
// 正确!组件名应该首字母大写:
function Hello(props) {
// 正确!div 是有效的 HTML 标签:
return
在运行时选择类型
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// 错误!JSX 标签名不能为一个表达式。
return
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
JSX的属性(Props)
使用 JavaScript 表达式作为属性
{}
括起来。例如,在这个 JSX 中:MyComponent
来说, props.foo
的值为 10,这是 1 + 2 + 3 + 4
表达式计算得出的。if
语句和 for
循环在 JavaScript 中不是表达式,因此它们不能直接在 JSX 中使用,但是你可以将它们放在周围的代码中。例如:function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) {
description = even;
} else {
description = odd;
}
return
字符串常量
属性默认为“True”
true
。因此下面两个 JSX 是等价的:{foo}
是 {foo: foo}
的简写,而不是 {foo: true}
。这里能这样用,是因为它符合 HTML 的做法。展开属性
props
对象,并且想在 JSX 中传递它,你可以使用 ...
作为“展开(spread)”操作符来传递整个属性对象。下面两个组件是等效的:function App1() {
return
const Button = props => {
const { kind, ...other } = props;
const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
return ;
};
const App = () => {
return (
kind
属性被安全地使用,不会传递到DOM中的 元素。其他的属性通过
...other
传递,使得组件变得非常灵活。你可以观察到 onClick
and children
属性都被传递了下去。JSX中的子代
props.children
。有几种不同的方法来传递子代:字符串字面量
props.children
就是那个字符串。这对于许多内置 HTML 元素很有用。例如:MyComponent
的 props.children
值将会直接是 "hello world!"
。因为 HTML 未转义,所以你可以像写 HTML 一样写 JSX:JSX子代
render() {
// 不需要使用额外的元素包裹数组中的元素!
return [
// 不要忘记 key :)
JavaScript 表达式作为子代
{}
包裹的 JavaScript 表达式作为子代传递。例如,下面这些表达式是等价的:function Item(props) {
return
{todos.map((message) =>
);
}
function Hello(props) {
return
函数作为子代
props.children
可以像其它属性一样传递任何种类的数据,而不仅仅是 React 知道如何去渲染的数据种类。例如,如果你有一个自定义组件,你能使其取一个回调作为props.children
:// Calls the children callback numTimes to produce a repeated component
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return
布尔值、Null 和 Undefined 被忽略
false
、null
、undefined
和 true
都是有效的子代,只是它们不会被渲染。下面的JSX表达式将渲染为相同的东西:
showHeader
为true
时渲染
组件。0
),它们依然会被React渲染。例如,下面的代码不会像你预期的那样运行,因为当 props.message
为空数组时,它会打印0
:&&
前面的表达式始终为布尔值:false
、true
、null
或 undefined
出现在输出中,你必须先把它转换成字符串 :