ReactJS 教程

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 事件 ReactJS - 状态管理 ReactJS - 状态管理 API ReactJS - 无状态组件 ReactJS - Hooks 进行状态管理 ReactJS - Hooks 的组件生命周期 ReactJS - 布局组件 ReactJS - 分页 ReactJS - Material UI ReactJS - Http 客户端编程 ReactJS - 表单编程 ReactJS - 受控组件 ReactJS - 非受控组件 ReactJS - Formik ReactJS - 条件渲染 ReactJS - 列表 ReactJS - Key 键 ReactJS - 路由 ReactJS - Redux ReactJS - 动画 ReactJS - Bootstrap ReactJS - Map ReactJS - 表格 ReactJS - 使用 Flux 管理状态 ReactJS - 测试 ReactJS - CLI 命令 ReactJS - 构建和部署 ReactJS - 示例

Hooks

ReactJS - Hooks 简介 ReactJS - 使用 useState ReactJS - 使用 useEffect ReactJS - 使用 useContext ReactJS - 使用 useRef ReactJS - 使用 useReducer ReactJS - 使用 useCallback ReactJS - 使用 useMemo ReactJS - 自定义 Hooks

ReactJS 高级

ReactJS - 可访问性 ReactJS - 代码拆分 ReactJS - 上下文 ReactJS - 错误边界 ReactJS - 转发 Refs ReactJS - 片段 ReactJS - 高阶组件 ReactJS - 与其他库集成 ReactJS - 优化性能 ReactJS - Profiler API ReactJS - Portals ReactJS - 不使用 ES6 ECMAScript ReactJS - 不使用 JSX 的 React ReactJS - Reconciliation ReactJS - Refs 和 DOM ReactJS - 渲染道具 ReactJS - 静态类型检查 ReactJS - 严格模式 ReactJS - Web 组件

其他概念

ReactJS - 日期选择器 ReactJS - Helmet ReactJS - 内联样式 ReactJS - PropTypes ReactJS - BrowserRouter ReactJS - DOM ReactJS - 轮播 ReactJS - 图标 ReactJS - 表单组件 ReactJS - 参考 API

ReactJS 有用资源

ReactJS - 快速指南 ReactJS - 备忘录 Axios - 备忘录 ReactJS - 有用资源 ReactJS - 讨论


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 AppRollup bundler 创建一个新的 React 应用程序 react-clock-hook-app

步骤 2 −在您最喜欢的编辑器中打开应用程序。

在应用程序的根目录下创建 src 文件夹。

src 文件夹下创建 components 文件夹。

src/components 文件夹下创建文件 Clock.js 并开始编辑。

导入 React 库 和 React 状态 Hook,setState

import React, { useState } from 'react';

步骤 2 −创建 Clock 组件。

function Clock() {
}

创建状态Hooks(钩子)来维护日期和时间。

const [currentDateTime, setCurrentDateTime] = useState(new Date());

设置每秒的日期和时间。

setInterval(() => setCurrentDateTime(new Date()), 1000);

使用 currentDateTime 创建用户界面以显示当前日期和时间并返回它。

return ( <div><p>当前时间为 {currentDateTime.toString()}</p></div> );

步骤 3 − 最后,使用代码片段 − 导出组件

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:

接下来,在 src 文件夹下创建一个文件 index.js,并使用 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')
);

最后,在根文件夹下创建public文件夹,并创建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 命令为应用程序提供服务。

npm start

打开浏览器,在地址栏中输入 http://localhost:3000,然后按回车键。应用程序将显示时间并每秒更新一次。

The current time is Wed Nov 11 2020 10:10:18 GMT+0530 (India Standard Time)

上述应用程序运行良好。但是,设置为每秒执行的 setCurrentDateTime() 必须在应用程序结束时删除。我们可以使用 React 提供的另一个 Hook,useEffect 来做到这一点。我们将在下一章(组件生命周期)中学习它。

在Expense Manager(费用管理器)应用程序中引入状态

让我们通过在本章中添加一个简单的功能来使用 Hooks 删除费用项目,从而在Expense Manager(费用管理器)应用程序中引入状态管理。

步骤 1 −在您最喜欢的编辑器中打开 expense-manager 应用程序。

src/components 文件夹下创建一个新文件 ExpenseEntryItemListFn.js 并开始编辑。

导入 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 命令为应用程序提供服务。

npm start

接下来,打开浏览器并在地址栏中输入 http://localhost:3000 并按回车键。

最后,要删除费用项目,请单击相应的删除链接。它将删除相应的项目并刷新用户界面,如动画 gif 所示。

Interface