React - 嵌套组件
React component 是 React 应用程序的构建块。本章将学习如何创建新的 React component 以及 React component 的特性。
React component 表示网页中用户界面的一个小块。React component 的主要任务是渲染其用户界面,并在内部 state 发生变化时更新它。除了渲染 UI 外,它还管理属于其用户界面的 events。总结来说,React component 提供以下功能。
- 用户界面的初始渲染。
- 事件的管理和处理。
- 内部 state 发生变化时更新用户界面。
React component 使用以下三个概念来实现这些特性 −
Properties − 使 component 能够接收输入。
Events − 使 component 能够管理 DOM events 和最终用户交互。
State − 使 component 能够保持有状态。有状态的 component 会根据其 state 更新 UI。
React 中有两种类型的 components。它们是 −
Function Components
Class Components
Function Components
Function component 实际上就是用 JavaScript functions 定义的。这个 React component 接受单个对象参数并返回一个 React element。请注意,React 中的 element 不是 component,但 component 由多个 elements 组成。以下是 React 中 function component 的语法:
function function_name(argument_name) {
function_body;
}
Class Components
类似地,class components 是由多个 functions 组成的基本 classes。React 的所有 class components 都是 React.Component class 的子类,因此 class component 必须始终扩展它。以下是基本语法 −
class class_name extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
让我们在接下来的章节中逐一学习所有这些概念。
创建 React component
React library 有两种 component 类型。这些类型根据创建方式进行分类。
- Function component − 使用普通的 JavaScript function。
- ES6 class component − 使用 ES6 class。
Function component 和 class component 的核心区别是 −
Function components 非常简洁。其唯一要求是返回一个 React element。
function Hello() {
return '<div>Hello</div>'
}
使用 ES6 class component 可以实现相同的功能,但需要少量额外的编码。
class ExpenseEntryItem extends React.Component {
render() {
return (
<div>Hello</div>
);
}
}
Class components 开箱即用地支持 state 管理,而 function components 不支持 state 管理。但是,React 为 function components 提供了 hook useState(),以维护其 state。
Class component 具有生命周期,并通过专用的 callback APIs 访问每个生命周期事件。Function component 没有生命周期。同样,React 为 function component 提供了 hook useEffect(),以访问 component 的不同阶段。
创建 class 组件
让我们在我们的 expense-manager 应用中创建一个新的 React 组件 ExpenseEntryItem,用于展示一个支出条目。支出条目包括名称、金额、日期和类别。支出条目的对象表示形式如下 −
{
'name': 'Mango juice',
'amount': 30.00,
'spend_date': '2020-10-10'
'category': 'Food',
}
在你喜欢的编辑器中打开 expense-manager 应用。
接下来,在 src/components 文件夹下创建一个文件 ExpenseEntryItem.css,用于为我们的组件添加样式。
接下来,在 src/components 文件夹下创建一个文件 ExpenseEntryItem.js,通过扩展 React.Component 来实现。
import React from 'react';
import './ExpenseEntryItem.css';
class ExpenseEntryItem extends React.Component {
}
接下来,在 ExpenseEntryItem class 中创建一个 render 方法。
class ExpenseEntryItem extends React.Component {
render() {
}
}
接下来,使用 JSX 创建用户界面,并从 render 方法中返回它。
class ExpenseEntryItem extends React.Component {
render() {
return (
<div>
<div><b>Item:</b> <em>Mango Juice</em></div>
<div><b>Amount:</b> <em>30.00</em></div>
<div><b>Spend Date:</b> <em>2020-10-10</em></div>
<div><b>Category:</b> <em>Food</em></div>
</div>
);
}
}
接下来,将组件指定为默认导出 class。
import React from 'react';
import './ExpenseEntryItem.css';
class ExpenseEntryItem extends React.Component {
render() {
return (
<div>
<div><b>Item:</b> <em>Mango Juice</em></div>
<div><b>Amount:</b> <em>30.00</em></div>
<div><b>Spend Date:</b> <em>2020-10-10</em></div>
<div><b>Category:</b> <em>Food</em></div>
</div>
);
}
}
export default ExpenseEntryItem;
现在,我们成功创建了我们的第一个 React 组件。让我们在 index.js 中使用我们新创建的组件。
import React from 'react';
import { createRoot } from 'react-dom/client';
import ExpenseEntryItem from './components/ExpenseEntryItem'
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<ExpenseEntryItem />);
示例
同样的功能也可以在网页中使用 CDN 来实现,如下所示 −
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React application :: ExpenseEntryItem component</title>
</head>
<body>
<div id="react-app"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
class ExpenseEntryItem extends React.Component {
render() {
return (
<div>
<div><b>Item:</b> <em>Mango Juice</em></div>
<div><b>Amount:</b> <em>30.00</em></div>
<div><b>Spend Date:</b> <em>2020-10-10</em></div>
<div><b>Category:</b> <em>Food</em></div>
</div>
);
}
}
ReactDOM.render(
<ExpenseEntryItem />,
document.getElementById('react-app') );
</script>
</body>
</html>
接下来,使用 npm 命令启动应用。
npm start
输出
接下来,打开浏览器,在地址栏输入 http://localhost:3000 并按回车。
Item: Mango Juice Amount: 30.00 Spend Date: 2020-10-10 Category: Food
创建 function component
React component 也可以使用普通的 JavaScript function 创建,但功能有限。基于 function 的 React component 不支持 state 管理和其他高级功能。它可以用来快速创建简单的 component。
上面的 ExpenseEntryItem 可以按照以下方式重写为 function −
function ExpenseEntryItem() {
return (
<div>
<div><b>Item:</b> <em>Mango Juice</em></div>
<div><b>Amount:</b> <em>30.00</em></div>
<div><b>Spend Date:</b> <em>2020-10-10</em></div>
<div><b>Category:</b> <em>Food</em></div>
</div>
);
}
在这里,我们只包含了 render 功能,这就足以创建一个简单的 React component。
拆分组件
即使 JavaScript 被认为更容易执行,但很多时候由于相对简单的项目中大量的 class 或依赖关系,代码会变得复杂。而且随着代码量的增大,浏览器中的加载时间会变长,从而降低性能效率。这就是 code-splitting 可以派上用场的地方。Code splitting 用于将组件或 bundle 分割成更小的块,以提高性能。
Code splitting 只会加载浏览器当前需要的组件。这个过程被称为 lazy load。这将极大地提升应用的性能。需要注意的是,我们并不是试图减少代码量,而只是试图通过加载用户可能永远不会需要的组件来减轻浏览器的负担。让我们看一个示例代码。
示例
让我们先看一个示例应用的打包代码,用于执行任何操作。
// file name = app.js
import { sub } from './math.js';
console.log(sub(23, 14));
// file name = math.js
export function sub(a, b) {
return a - b;
}
上面的应用的 Bundle 将如下所示 −
function sub(a, b) {
return a - b;
}
console.log(sub(23, 14));
现在,在应用中引入 code splitting 的最佳方式是使用 dynamic import()。
// Before code-splitting
import { sub } from './math';
console.log(add(23, 14));
// After code-splitting
import("./math").then(math => {
console.log(math.sub(23, 14));
});
当使用这种语法(在像 Webpack 这样的 bundle 中)时,code-splitting 将自动开始。但是如果你使用 Create React App,code-splitting 已经为你配置好了,你可以立即开始使用。