JSX 就是 React.createElement(component, props, ...children) 函数的语法糖。
指定 React 元素类型 component
-
由于 JSX 会编译为函数
React.createElement的调用,因此 React 库和 React 组件所在作用域必须位于 JSX 的作用域链上。 -
JSX 中可以使用点语法来引用 React 组件,这可以方便地从一个模块中导出多个 React 组件。
-
JSX 中,小写字母开头的元素代表 HTML 内置组件,最终会编译为字符串传给
React.createElement的第一个参数;大写字母开头的元素代表自定义 React 组件,最终会编译为命名变量的直接引用传给React.createElement的第一个参数。React 建议使用大写字母开头命名自定义组件,或者在 JSX 使用自定义组件之前,将其赋值给一个大写字母开头的变量。 -
通用 JavaScript 表达式无法作为 React 元素类型。如果想用通用表达式来动态决定元素类型,可以在 JSX 使用它之前将其赋值给一个大写字母开头的变量。这通常用于根据 prop 来渲染不同组件的情形。
import React from "react";
import CustomButton from "./CustomButton";
const MyComponents = {
CustomButton,
};
const MyButtons = {
warning: function WarningButton() {
// React.createElement(MyComponents.CustomButton, {color: "yellow"}, null);
return <MyComponents.CustomButton color="yellow" />;
},
error: function ErrorButton() {
return <MyComponents.CustomButton color="red" />;
},
};
function Buttons(props) {
const SpecificButton = MyButtons[props.buttonType];
// React.createElement('div', null, React.createElement(SpecificButton), React.createElement(SpecificButton));
return (
<div>
<SpecificButton />
<SpecificButton />
</div>
);
}
指定属性 props
-
JavaScript 表达式
if、for语句不是表达式,不能直接传给 prop,但是可用于条件渲染或创建列表。 -
字符串字面量
字符串字面量赋值给 prop 时,它的值是未转义的。
-
没有值的 prop 默认值为
true为避免与 ES6 对象简写混淆,React 不建议没有 value 的 prop。
-
属性展开
使用展开运算符可以将整个对象传给 React 元素的 props。属性展开在某些情况下很有用,但是也很容易把不必要的 props 传给不相关的组件,或者将无效的 HTML 属性传递给 DOM,React 建议慎用这种语法。
import React from "react";
import Tooltip from "./Tooltip";
import MyTextBox from "./MyTextBox";
function Example(props) {
const defaultProps = {
text: "MyTextBox",
autocomplete: true,
};
return (
<Tooltip title={`box ${props.id}`}>
<MyTextBox text="MyTextBox" autocomplete />
<MyTextBox {...defaultProps} />
</Tooltip>
);
}
指定子元素 children
包含在开始和结束标签之间的 JSX 表达式内容,将传递给外层组件特定属性 props.children。
-
字符串字面量
开始和结束标签之间只有一个字符串,那么
props.children就是该未转义字符串,这对于内置的 HTML 标签很有用。JSX 会移除行首尾的空格以及空行,与标签相邻的空行直接删除,文本字符串之间的空行会被压缩为一个空格。 -
JSX
子元素可以是一个或多个 JSX 元素,也可以将不同类型的子元素混合起来。React 组件允许返回由 JSX 元素所构成的数组。
-
JavaScript 表达式
JavaScript 表达式包裹在
{}中作为子元素,这对于展示任意长度的列表很有用。JavaScript 表达式也可以和其它类型子元素结合起来使用,这种做法可以方便地替代模板字符串。 -
函数
JSX 中的 JavaScript 表达式会被计算为相应的值,如:字符串、列表、React 元素等。
props.children和其它 prop 一样,可以接收任何类型的数据,如:函数,而不必是已知的 React 可渲染类型,只要确保该组件渲染前能被转换为 React 理解的对象即可。这种做法不常见,但可以扩展 JSX。 -
布尔类型、
null、undefined不会被渲染null、undefined、true、false是合法的子元素,但不会被渲染,这有助于依据特定条件来渲染其它 React 元素。其它类型的数据,即使 truthiness 为false,也会被渲染。
import React from "react";
import MyElement from "./MyElement";
import Item from "./Item";
import Content from "./Content";
import Header from "./Header";
function Example(props) {
const toDos = ["finish doc", "submit pr"];
return props.type !== "array" ? (
<div>
Hello World
<MyElement>{"foo"} bar</MyElement>
<div>
{toDos.map((item) => (
<Item key={item} message={item} />
))}
</div>
</div>
) : (
[<li key={"a"}>A</li>, <li key={"b"}>B</li>]
);
}
function List(props) {
return (
<div>
{new Array(props.nums).map((num) => {
return props.children(num);
})}
</div>
);
}
function FnTest() {
return <List nums={10}>{(num) => <div key={num}>item {num}</div>}</List>;
}
function Test(props) {
return (
<div>
{props.showHeader && <Header />}
<Content />
</div>
);
}
不使用 JSX
React 不强制使用 JSX,如果不想在构建环境中配置有关 JSX 的编译,可以直接使用 React.createElement(component, props, ...children) 函数。该函数的第一个参数 component 可以是字符串、React.Component 的子类、函数。
为 React.createElement 函数创建快捷方式,可以更加方便地使用无 JSX 的 React。
import React from "react";
import ReactDOM from "react-dom/client";
const h = React.createElement;
class Hello extends React.Component {
render() {
return h("div", null, `Hello ${this.props.name}`);
}
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(h(Hello, { name: "React.createElement" }, null));