React组件都是以JSX语法来编写组件的。JSX其实并不复杂,它本质上是一种JavaScript的语法糖(也可以近似理解为一种模板引擎),用于实现JavaScript和HTML的混写(即HTML in JS),思路很像PHP、JSP这类后端模板语言,只不过JSP是编译为Java代码在服务端Tomcat容器中运行,而JSX最终会编译为JavaScript在浏览器中运行,我们这里简单介绍一些JSX的常见用法。
JSX是JavaScript的语法扩展,它的语法专门适用于编写React组件,我们可以使用.js
或是.jsx
作为文件后缀,大部分现代IDE或是文本编辑器都能正确识别。早期版本中JSX文件必须引入React才能使用,即import React from 'react'
,但在React17后这一反直觉的限制取消了。
此外,对于TypeScript,也有对应的TSX。
JSX中可以混写HTML、CSS、JavaScript这3种源代码,下面是一个例子。
const App = () => {
return <div style={{ backgroundColor: "#ff0000" }}>Hello</div>;
};
export default App;
代码中,我们定义组件的逻辑大部分使用了JavaScript,但输出内容使用的是HTML,其中<div>
的样式我们使用了内联CSS,但它的写法和在HTML文件中不同,JSX中的写法更类似于给style
指定一个对象,对象内部有一个叫做backgroundColor
的字段,它的值是一个字符串。
不过实际开发中,对于大段的CSS可能还是单独抽离到文件中比较合适,前端有很多CSS样式加载方案,比如CSS Module方案,可以将CSS样式表文件以JavaScript对象的形式加载到组件中。
JSX中使用循环渲染和条件渲染,通常需要在返回的HTML中插入JavaScript代码。这两者的写法原理其实是一样的,这里简单起见我们就以循环渲染为例进行介绍。下面例子中,在HTML里插入了JavaScript代码实现了循环渲染。
import { useState } from "react";
const App = () => {
const [data, setData] = useState({
list: ["apple", "banana", "orange"],
});
return (
<div>
{data.list.map((s, index) => {
return (
<div key={index}>
{s}
<br />
</div>
);
})}
</div>
);
};
export default App;
JavaScript代码需要用大括号包裹(否则会被当作普通的HTML文本处理),我们使用map()
函数循环了一个数组,将JavaScript字符串数组转换成了包含JSX元素的数组,因此实际上我们的return
返回值还是一段完整的HTML。这里注意React要求JSX中使用循环渲染必须给被渲染的元素加唯一的key
属性。
实际上,我们也可以将一些复杂的渲染逻辑抽离到单独的函数中,只要函数返回值是JSX它们就可以嵌入到组件的返回值中,下面是一个例子。
import { useState } from "react";
const renderDataList = (dataList) => {
return dataList.list.map((s, index) => {
return (
<div key={index}>
{s}
<br />
</div>
);
});
};
const App = () => {
const [data, setData] = useState({
list: ["apple", "banana", "orange"],
});
return <div>{renderDataList(data)}</div>;
};
export default App;
JSX支持一种特殊的标签<>
。前面说过组件的返回值必须存在根节点,但有时候我们希望组件输出的HTML并不是这样的,而强行引入一个<div>
作为根节点还会破坏HTML的结构,此时我们可以使用空标签<>
。它仅用于包裹JSX的返回值,在实际的DOM中不会有真实的输出,下面是一个例子。
return <>{renderDataList(data)}</>;