- ReactJS 菜鸟教程
- ReactJS 教程
- ReactJS - 简介
- ReactJS - 安装
- ReactJS - 特性
- ReactJS - 优点和缺点
- ReactJS - 架构
- ReactJS - 创建 React 应用程序
- ReactJS - JSX
- ReactJS - 组件
- ReactJS - 嵌套组件
- ReactJS - 使用组件
- ReactJS - 组件集合
- ReactJS - 样式
- ReactJS - 属性(props)
- ReactJS - 使用属性创建组件
- ReactJS - props 验证
- ReactJS - 构造函数
- ReactJS - 组件生命周期
- ReactJS - 事件管理
- ReactJS - 创建事件感知组件
- ReactJS - 在Expense Manager APP中引入事件
- ReactJS - 状态管理
- ReactJS - 状态管理 API
- ReactJS - 无状态组件
- ReactJS - 使用 React Hooks 进行状态管理
- ReactJS - 使用 React 钩子的组件生命周期
- ReactJS - 组件的布局
- ReactJS - 分页
- ReactJS - Material 用户界面
- ReactJS - Http 客户端编程
- ReactJS - 表单编程
- ReactJS - 受控组件
- ReactJS - 不受控制的组件
- ReactJS - Formik
- ReactJS - 条件渲染
- ReactJS - 列表
- ReactJS - 键
- ReactJS - 路由
- ReactJS - 冗余
- ReactJS - 动画
- ReactJS - 引导程序
- ReactJS - 地图
- ReactJS - 表格
- ReactJS - 使用 Flux 管理状态
- ReactJS - 测试
- ReactJS - CLI 命令
- ReactJS - 构建和部署
- ReactJS - 示例
- ReactJS - 钩子简介
- ReactJS - 使用 useState
- ReactJS - 使用 useEffect
- ReactJS - 使用 useContext
- ReactJS - 使用 useRef
- ReactJS - 使用 useReducer
- ReactJS - 使用 useCallback
- ReactJS - 使用 useMemo
- ReactJS - 自定义钩子
- ReactJS - 可访问性
- ReactJS - 代码拆分
- ReactJS - 上下文
- ReactJS - 错误边界
- ReactJS - 转发引用
- ReactJS - 片段
- ReactJS - 高阶组件
- ReactJS - 与其他库集成
- ReactJS - 优化性能
- ReactJS - 分析器 API
- ReactJS - 门户
- ReactJS - 没有 ES6 ECMAScript 的 React
- ReactJS - 没有 JSX 的 React
- ReactJS - 协调
- ReactJS - 引用和 DOM
- ReactJS - 渲染属性
- ReactJS - 静态类型检查
- ReactJS - 严格模式
- ReactJS - Web 组件
- ReactJS - 日期选择器
- ReactJS - Helmet
- ReactJS - 内联样式
- ReactJS - 属性类型
- ReactJS - 浏览器路由器
- ReactJS - DOM
- ReactJS - 旋转木马
- ReactJS - 图标
- ReactJS - 表单组件
- ReactJS - 参考 API
ReactJS - 使用 React Hooks 进行状态管理
React 从 React 16.8 中引入了一个全新的概念,称为 React Hooks。尽管这是一个相对较新的概念,但它使 React 功能组件能够拥有自己的状态和生命周期。此外,React Hooks 使功能组件能够使用许多以前不可用的功能。在本章中,让我们看看如何使用 React Hooks 在功能组件中进行状态管理。
什么是 React Hooks?
React Hooks 是 React 提供的特殊函数,用于处理 React 功能组件内的特定功能。React 为每个受支持的特性提供了一个 Hook 函数。例如,React 提供了 useState() 函数来管理功能组件中的状态。当 React 功能组件使用 React Hooks 时,React Hooks 会将自身附加到组件中并提供额外的功能。
useState() Hook 的一般签名如下 -
const [<state variable>, <state update function>] = useState(<initial value>);
例如,使用 Hooks 的时钟组件中的状态管理可以按照下面指定的方式完成 -
const [currentDateTime, setCurrentDateTime] = useState(new Date());
setInterval(() => setCurrentDateTime(new Date()), 1000);
这里
- currentDateTime − 用于保存当前日期和时间的变量(由 setState() 返回)
- setCurrentDate() − 用于设置当前日期和时间的函数(由 setState() 返回))
创建有状态组件
在本章中,让我们使用 Hooks 重新创建时钟组件。
第 1 步 - 首先,按照创建 React 应用程序一章中的说明,使用 Create React App 或 Rollup bundler 创建一个新的 react 应用程序 react-clock-hook-app。
第 2 步 - 在您最喜欢的编辑器中打开应用程序。
在应用程序的根目录下创建 src 文件夹。
在 src 文件夹下创建 components 文件夹。
创建一个文件,Clock.js src/components 文件夹下并开始编辑。
导入 React 库和 React 状态 Hook、setState。
import React, { useState } from 'react';
第 3 步 - 创建时钟组件。
function Clock() {
}
创建状态 Hooks 以维护日期和时间。
const [currentDateTime, setCurrentDateTime] = useState(new Date());
为每秒设置日期和时间。
setInterval(() => setCurrentDateTime(new Date()), 1000);
创建用户界面以使用 currentDateTime 显示当前日期和时间,并返回它。
return ( <div><p>The current time is {currentDateTime.toString()}</p></div> );
第 4 步 - 最后,使用代码片段导出组件 -
export default Clock;
Clock组件的完整源代码如下:
import React, { useState } from 'react';
function Clock(props) {
const [currentDateTime, setCurrentDateTime] = useState(new Date());
setInterval(() => setCurrentDateTime(new Date()), 1000);
return (
<div><p>The current time is {currentDateTime.toString()}</p></div>
);
}
export default Clock;
index.js:
接下来,创建一个文件,index.js src 文件夹下并使用 Clock 组件。
import React from 'react';
import ReactDOM from 'react-dom';
import Clock from './components/Clock';
ReactDOM.render(
<React.StrictMode>
<Clock />
</React.StrictMode>,
document.getElementById('root')
);
最后,在根文件夹下创建一个公共文件夹,并创建index.html文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Clock</title>
</head>
<body>
<div id="root"></div>
<script type="text/JavaScript" src="./index.js"></script>
</body>
</html>
然后,使用 npm 命令为应用程序提供服务。
打开浏览器,在地址栏中输入 http://localhost:3000,然后按回车键。该应用程序将显示时间并每秒更新一次。
上述应用程序运行良好。但是,设置为每秒执行一次的 setCurrentDateTime() 在应用程序结束时必须删除。我们可以使用 React 提供的另一个 Hook,useEffect 来做到这一点。我们将在下一章(组件生命周期)中学习它。
在费用管理器应用程序中引入状态
在本章中,我们通过添加一个简单的功能来使用 Hooks 删除费用项目,从而在费用管理器应用程序中介绍状态管理。
第 1 步 - 在您最喜欢的编辑器中打开费用管理器应用程序。
创建一个新文件,ExpenseEntryItemListFn.js src/components 文件夹下并开始编辑。
导入 React 库和 React 状态 Hook、setState。
import React, { useState } from 'react';
导入 css,ExpenseEntryItem.css。
import './ExpenseEntryItemList.css'
第 2 步 - 创建 ExpenseEntryItemListFn 组件。
function ExpenseEntryItemListFn(props) { }
使用通过属性传递到组件中的费用项初始化组件的状态钩子。
const [items, setItems] = useState(props.items);
第 3 步 - 创建事件处理程序以突出显示行。
function handleMouseEnter(e) {
e.target.parentNode.classList.add("highlight");
}
function handleMouseLeave(e) {
e.target.parentNode.classList.remove("highlight");
}
function handleMouseOver(e) {
console.log("The mouse is at (" + e.clientX + ", " + e.clientY + ")");
}
第 4 步 - 创建事件处理程序以使用 items 和 setItems() 删除所选项目。
function handleDelete(id, e) {
e.preventDefault();
console.log(id);
let newItems = [];
items.forEach((item, idx) => {
if (item.id != id)
newItems.push(item)
})
setItems(newItems);
}
第 5 步 - 创建 getTotal() 方法以计算总金额。
function getTotal() {
let total = 0;
for (var i = 0; i < items.length; i++) {
total += items[i].amount
}
return total;
}
第 6 步 - 创建用户界面,通过循环覆盖项目来显示费用。
const lists = items.map((item) =>
<tr key={item.id} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<td>{item.name}</td>
<td>{item.amount}</td>
<td>{new Date(item.spendDate).toDateString()}</td>
<td>{item.category}</td>
<td><a href="#" onClick={(e) => handleDelete(item.id, e)}>Remove</a></td>
</tr>
);
第 7 步 - 创建完整的 UI 以显示费用并将其返回。
return (
<table onMouseOver={handleMouseOver}>
<thead>
<tr>
<th>Item</th>
<th>Amount</th>
<th>Date</th>
<th>Category</th>
<th>Remove</th>
</tr>
</thead>
<tbody>
{lists}
<tr>
<td colSpan="1" style={{ textAlign: "right" }}>Total Amount</td>
<td colSpan="4" style={{ textAlign: "left" }}>
{getTotal()}
</td>
</tr>
</tbody>
</table>
);
最后,导出函数,如下所示 -
export default ExpenseEntryItemListFn;
ExpenseEntryItemListFn的完整代码如下:
import React, { useState } from 'react';
import './ExpenseEntryItemList.css'
function ExpenseEntryItemListFn(props) {
const [items, setItems] = useState(props.items);
function handleMouseEnter(e) {
e.target.parentNode.classList.add("highlight");
}
function handleMouseLeave(e) {
e.target.parentNode.classList.remove("highlight");
}
function handleMouseOver(e) {
console.log("The mouse is at (" + e.clientX + ", " + e.clientY + ")");
}
function handleDelete(id, e) {
e.preventDefault();
console.log(id);
let newItems = [];
items.forEach((item, idx) => {
if (item.id != id)
newItems.push(item)
})
setItems(newItems);
}
function getTotal() {
let total = 0;
for (var i = 0; i < items.length; i++) {
total += items[i].amount
}
return total;
}
const lists = items.map((item) =>
<tr key={item.id} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<td>{item.name}</td>
<td>{item.amount}</td>
<td>{new Date(item.spendDate).toDateString()}</td>
<td>{item.category}</td>
<td><a href="#"
onClick={(e) => handleDelete(item.id, e)}>Remove</a></td>
</tr>
);
return (
<table onMouseOver={handleMouseOver}>
<thead>
<tr>
<th>Item</th>
<th>Amount</th>
<th>Date</th>
<th>Category</th>
<th>Remove</th>
</tr>
</thead>
<tbody>
{lists}
<tr>
<td colSpan="1" style={{ textAlign: "right" }}>Total Amount</td>
<td colSpan="4" style={{ textAlign: "left" }}>
{getTotal()}
</td>
</tr>
</tbody>
</table>
);
}
export default ExpenseEntryItemListFn;
index.js
更新index.js并包含 ExpenseEntyItemListFn 组件 -
import React from 'react';
import ReactDOM from 'react-dom';
import ExpenseEntryItemListFn from './components/ExpenseEntryItemListFn'
const items = [
{ id: 1, name: "Pizza", amount: 80, spendDate: "2020-10-10", category: "Food" },
{ id: 2, name: "Grape Juice", amount: 30, spendDate: "2020-10-12", category: "Food" },
{ id: 3, name: "Cinema", amount: 210, spendDate: "2020-10-16", category: "Entertainment" },
{ id: 4, name: "Java Programming book", amount: 242, spendDate: "2020-10-15", category: "Academic" },
{ id: 5, name: "Mango Juice", amount: 35, spendDate: "2020-10-16", category: "Food" },
{ id: 6, name: "Dress", amount: 2000, spendDate: "2020-10-25", category: "Cloth" },
{ id: 7, name: "Tour", amount: 2555, spendDate: "2020-10-29", category: "Entertainment" },
{ id: 8, name: "Meals", amount: 300, spendDate: "2020-10-30", category: "Food" },
{ id: 9, name: "Mobile", amount: 3500, spendDate: "2020-11-02", category: "Gadgets" },
{ id: 10, name: "Exam Fees", amount: 1245, spendDate: "2020-11-04", category: "Academic" }
]
ReactDOM.render(
<React.StrictMode>
<ExpenseEntryItemListFn items={items} />
</React.StrictMode>,
document.getElementById('root')
);
接下来,使用 npm 命令为应用程序提供服务。
接下来,打开浏览器并在地址栏中输入 http://localhost:3000,然后按回车键。
最后,要删除支出项目,请单击相应的删除链接。它将删除相应的项目并刷新用户界面,如动画 gif 中所示。