JSX 是 JavaScript 中的 JS 和 XML 中的 X 的综合体,是对 JavaScript 的扩展,使用一种基于标签的句法直接在 JavaScript 代码中定义 React 元素。JSX 也是一种创建 React 元素的方式。
在 JSX 中,元素的类型通过标签指定,标签的属性表示元素的属性,子元素添加在起始和结束标签之间。
React.createElement(IngredientsList, {list: [...]}, null) // IngredientsList 是自定义组件
JSX 看着眼熟,而且多数指令得到的句法都与 HTML 类似。然而,使用 JSX 时还是要注意一些事项。
JSX 是 JavaScript,可以直接在 JavaScript 函数中使用。例如,可以把数组映射为 JSX 元素:
{props.ingredients.map((ingredient, i) => (
- {ingredient}
))}
JSX 简洁,可读性高,但是浏览器无法解释。所有 JSX 都要转换成 createElement 调用。幸好,有一个工具可以胜任这项工作:Babel。
JavaScript 是一门解释型语言,浏览器把代码解释为文本,无须编译。然而,不是所有浏览器都支持最新的 JavaScript 句法,而且没有浏览器支持 JSX 句法。 由于我们想在 JSX 中使用最新的 JavaScript 特性,那就需要找到一种方式把我们写出的源码转换成浏览器可以解释的版本。这个过程叫作编译,Babel(https://babeljs.io)就是做这项工作的。
使用 Babel 的方式有很多种,最容易上手的是直接在 HTML 中通过 CDN 引入 Babel,编译类型为“text/babel”的脚本块中的代码。Babel 在客户端运行源码之前编译代码。这虽然不是在生产环境中使用 Babel 的最佳方式,却是开始着手使用 JSX 的好方法。
React Examples
JSX 的展开运算符用起来与对象的展开运算符一样。展开运算符将把 recipe 对象的每个字段作为属性传给 Recipe 组件。
{recipes.map((recipe, i) => (
))}
我们可以使用对象析构限定传给函数的变量。这样一来,我们便可以直接访问 title 和 recipes 变量,不用再加上 props 前缀。
const Menu = (props) => (
...
);
与
const Menu = ({ title, recipes }) => (
...
);
下面这个表达式把菜谱的名称转换成小写字符串,再把空格全局替换成连字符。
在浏览器的 React 开发者工具中,可以查看得到的虚拟 DOM。如果修改 recipes 数组的内容,然后重新渲染 Menu 组件,React 将尽可能高效地修改 DOM。
React 不在一个组件中渲染两个或以上毗邻元素或同辈元素,必须把这些元素放在一个标签内,例如一个 div 内。然而,这样会导致创建很多非必需的标签,产生很多没什么用的容器。使用 React 片段,我们可以模拟容器的行为,但不真正创建新标签。
function Cat({ name }) {
return (
xxx
yyy
);
}
这个标签后,控制台警告就没有了。function Cat({ name }) {
return (
<>
xxx
yyy
>
);
}
xxx
yyy
webpack 在宣传上称自己为模块打包工具,负责把各种文件(JavaScript、LESS、CSS、JSX、ESNext 等)汇集成一个文件。
除了编译代码之外,webpack 还可以处理以下事项。
使用 webpack 这类工具静态构建客户端 JavaScript,方便团队协同开发大型 Web 应用。采用模块打包工具 webpack 还可以获得以下好处:
有个可以自动生成预先配置好一切的工具,名为 CreateReact App。不过,这个工具隐藏了具体的步骤,在使用它之前我们要了解一下背后的机制。
如何从头开始设置一个 React 项目。
npm init -y
npm install react react-dom serve
import React from "react";
import ReactDOM from "react-dom";
import data from "../data/recipes.json";
import Menu from "./components/Menu";
ReactDOM.render(, document.getElementById("root"));
npm install --save-dev webpack webpack-cli
var path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.join(__dirname, "dist", "assets"),
filename: "bundle.js",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
};
npm install babel-loader @babel/core --save-dev
npm install @babel/preset-env @babel/preset-react --save-dev
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
npx webpack --mode development
"scripts": {
"build": "webpack --mode production"
},
npm run build
我们使用的 import 语句,目前多数浏览器和 Node.js 都不支持。但是,我们依然可以使用,因为在最终的代码中 Babel 将把 import 语句转换成 require(‘module/path’);。CommonJS 模块通常使用 require 函数。
我们把构建包导出到 dist 文件夹中,这个文件夹中就是要在 Web 服务器中运行的文件。index.html 文件应该放在 dist 文件夹中。这个文件中应该有一个 div 元素,用于挂载 React Menu 组件。此外,还要有一个 script 标签,加载打包好的 JavaScript。
React Recipes App
把代码打包进一个文件,在浏览器中调试应用可能有些不便。为了缓解这方面的问题,我们可以提供源码映射(source mapping)。源码映射把构建包映射到源文件上。使用 webpack,我们只需要在 webpack.config.js 文件中添加几行代码:
// 在 webpack.config.js 中设置源码映射
module.exports = {
...
devtool: "#source-map" // 添加这个选项,开启源码映射
}
源码映射的作用是方便我们使用源码文件调试。在浏览器开发者工具的“Sources”标签页中,你会看到一个名为 webpack:// 的文件夹。这个文件夹中是构建包里的所有源码文件。你可以使用浏览器中的单步调试器调试这些文件。任何点击一个行号即可添加一个断点。刷新浏览器,JavaScript 将在运行到源码文件中的断点处暂停。你可以在“Scope”面板中查看作用域中的变量,或者在“Watch”面板中添加要监视的变量。
Create React App(https://github.com/facebook/create-react-app) 是一个命令行工具,能自动生成 React 项目。Create React App 目的是帮助开发者快速创建 React 项目,不用再自己动手配置 webpack、Babel、ESLint 等相关的工具。
npm install -g create-react-app
create-react-app my-project
学习 React 时,如果不想自己定制 webpack 构建过程,还可以使用 CodeSandbox。这是一个在线 IDE,地址为 https://codesandbox.io。