如何使用ReactHooks创建倒数计时器

来自菜鸟教程
跳转至:导航、​搜索

介绍

在本教程中,您将使用 React 钩子创建倒数计时器,以更新状态并管理 React 组件中的副作用。

使用 React 钩子,您可以创建更简洁的代码、组件之间的可重用逻辑以及无需类即可更新状态。

倒数计时器是一个常见的 UI 组件。 他们可以与用户交流他们做某事的时间或距离某事件发生的时间。 您将在本教程中倒计时的活动是 DigitalOcean 的 Hacktoberfest

在本教程结束时,您将拥有一个使用 React 的 useState()useEffect() 钩子的功能性和可重用的倒计时计时器。

先决条件

在开始本指南之前,您需要以下内容:

本教程已使用 Node.js v16.13.1、npm v8.2.0 和 react v17.0.2 进行了验证。

第 1 步——创建一个空项目

在这一步中,您将使用 Create React App 创建一个新项目。 然后,您将删除引导项目时安装的示例项目和相关文件。

首先,创建一个新项目。 在您的终端中,运行以下脚本以使用 create-react-app 安装新项目:

npx create-react-app react-hooks-timer

项目完成后,进入目录:

cd react-hooks-timer

在新的终端选项卡或窗口中,使用 Create React App 启动脚本 启动项目。 浏览器将自动刷新更改,因此请在您工作时保持此脚本运行:

npm start

您将获得一个本地运行的服务器。 如果项目没有在浏览器窗口中打开,您可以使用 http://localhost:3000/ 打开它。 如果您从远程服务器运行它,地址将是 http://your_server_ip:3000

您的浏览器将加载由 Create React App 生成的 React 应用程序:

您将构建一组新的自定义组件,因此您需要首先清除一些样板代码,以便您可以拥有一个空项目。

首先,在文本编辑器中打开 src/App.js。 这是注入页面的根组件。 所有组件都将从这里开始。 你可以在 How To Set Up a React Project with Create React App 中找到有关 App.js 的更多信息。

使用以下命令打开 src/App.js

nano src/App.js

你会看到一个像这样的文件:

反应钩子定时器/src/App.js

import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

然后替换 return 语句中的所有内容以返回一组 <div> 标记。 这将为您提供一个不返回任何内容的有效页面。 最终代码将如下所示:

反应钩子定时器/src/App.js

import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div>
    </div>
  )
}

export default App;

接下来,删除徽标。 删除行 import logo from './logo.svg';

保存并退出文本编辑器。

最后,删除徽标,因为您不会在此应用程序中使用它。 最好在工作时删除未使用的文件以避免混淆。

在终端窗口中键入以下命令:

rm src/logo.svg

现在项目已经建立,您可以创建您的第一个组件。

第 2 步 — 计算剩余时间

在这一步中,您将创建一个函数来计算当前日期和 Hacktoberfest 第一天之间的剩余时间。

首先,设置一个名为 calculateTimeLeft 的函数:

反应钩子定时器/src/App.js

// ...

const calculateTimeLeft = () => {

};

// ...

接下来,在函数内部,您将使用 JavaScript Date 对象来查找当前的 year

创建一个名为 year 的变量,该变量设置为 JavaScript date 方法 Date.getFullYear()

calculateTimeLeft 函数中添加以下代码:

反应钩子定时器/src/App.js

// ...

const calculateTimeLeft = () => {
  let year = new Date().getFullYear();
}

// ...

注意: 您可以使用 JavaScript Date 对象来处理日期和时间。


Date.getFullYear() 方法将获取当前年份。

您现在可以使用此变量来计算当前日期与 Hacktoberfest 第一天之间的差异。

calculateTimeLeft 函数中,添加一个名为 difference 的新变量。 使用以下代码将其设置为新的 Date 对象:

反应钩子定时器/src/App.js

// ...

const calculateTimeLeft = () => {
  let year = new Date().getFullYear();

  const difference = +new Date(`10/01/${year}`) - +new Date();
}

// ...

新的 Date 对象之前的 + 是告诉 JavaScript 将对象转换为整数的简写,它为您提供对象的 Unix 时间戳,表示为自纪元以来的微秒。

注意: 对于本教程,请确保您的倒计时日期设置在将来,否则您会遇到错误。


为了保持代码可重用,您使用 JavaScript Template Literal 并添加 year 变量以及 Hacktoberfest 的月份和日期。 Hacktoberfest 每年 10 月 1 日开始。 当您使用 year 变量代替硬编码年份时,您将始终拥有当前年份。

现在您计算了倒数计时器到期前的总毫秒数,您需要将毫秒数转换为更友好和更易于阅读的值。

第 3 步 - 格式化为天、小时、分钟和秒

在此步骤中,您将创建一个名为 timeLeft 的空对象,使用 if 语句检查是否有剩余时间,并使用数学计算总小时数、分钟数和秒数和模数 (%) 运算符。 最后,您将返回 timeLeft

首先,创建名为 timeLeft 的空对象,然后在 if 语句中填充天、小时、分钟和秒。

calculateTimeLeft 函数中添加以下代码:

反应钩子定时器/src/App.js

// ...

const calculateTimeLeft = () => {
  let year = new Date().getFullYear();
  let difference = +new Date(`10/01/${year}`) - +new Date();

  let timeLeft = {};
}

// ...

现在创建一个 if 语句,它将比较 difference 变量以查看它是否大于 0

calculateTimeLeft 函数中添加以下代码:

反应钩子定时器/src/App.js

// ...

const calculateTimeLeft = () => {
  let year = new Date().getFullYear();
  let difference = +new Date(`10/01/${year}`) - +new Date();

  let timeLeft = {};

  if (difference > 0) {
    timeLeft = {
      days: Math.floor(difference / (1000 * 60 * 60 * 24)),
      hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
      minutes: Math.floor((difference / 1000 / 60) % 60),
      seconds: Math.floor((difference / 1000) % 60)
    };
  }
}

// ...

在此代码中,您将数字从天、小时、分钟和秒向下舍入,然后去掉余数以获得整数值。 然后您可以比较 difference 以查看它是否大于 0

最后,您需要返回 timeLeft 以便您可以在组件的其他位置使用该值。

calculateTimeLeft 函数中添加以下代码:

反应钩子定时器/src/App.js

// ...

const calculateTimeLeft = () => {
  let year = new Date().getFullYear();
  let difference = +new Date(`10/01/${year}`) - +new Date();

  let timeLeft = {};

  if (difference > 0) {
    timeLeft = {
      days: Math.floor(difference / (1000 * 60 * 60 * 24)),
      hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
      minutes: Math.floor((difference / 1000 / 60) % 60),
      seconds: Math.floor((difference / 1000) % 60)
    };
  }

  return timeLeft;
}

// ...

现在您已经创建了一个计算距离 Hacktoberfest 还剩时间的函数,您可以添加将控制和更新计时器的应用程序状态。

第 4 步 — 使用 useStateuseEffect 更新您的应用程序状态

使用 React Hooks,您可以将状态管理功能添加到现有的功能组件中,而无需将它们转换为类。

在此步骤中,您将从 React 导入 useStateuseEffect 挂钩以管理此组件中的状态。

App.js 文件的顶部,在导入语句中添加 useStateuseEffect

反应钩子定时器/src/App.js

import React, { useEffect, useState } from "react";

// ...

这段代码告诉 React 你想使用这些特定的钩子和它们在 React 中可用的功能。

要使倒数计时器工作,您需要连接我们之前编写的用于更新状态的剩余时间方法:

calculateTimeLeft 函数之后添加此代码:

反应钩子定时器/src/App.js

// ...

const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());

// ...

这种 JavaScript 语法称为 数组解构

useState 方法接受一个参数来设置初始状态,并返回一个包含当前状态的数组和一个设置状态的函数。

timeLeft 将携带我们的时间间隔对象,并为我们提供设置状态的方法。 在组件加载时,timeLeft 值设置为当前剩余时间值。

接下来,您将使用 useEffect 挂钩来处理组件的副作用。

注意: 副作用 是任何影响正在执行的函数范围之外的东西的东西。


在此解决方案中,您将在 useEffect 挂钩内使用 setTimeout 方法。 setTimeout 和类似的 setInterval 方法是在 useEffect 钩子内部使用时常见的 React 模式。

大多数异步行为,如 React 中的 setTimeout 方法,都是使用 useEffectuseState 挂钩定义的。

注意: 您可以在 React Docs 的这一部分阅读更多关于何时以及如何使用 setTimeoutsetInterval 等方法的信息。


useState() 函数之后添加此代码:

反应钩子定时器/src/App.js

// ...

const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());

useEffect(() => {
  const timer = setTimeout(() => {
    setTimeLeft(calculateTimeLeft());
  }, 1000);
});

// ...

useEffect 更新剩余时间。 默认情况下,React 会在每次渲染后重新调用效果。

每次在状态中更新变量 timeLeft 时,都会触发 useEffect。 每次触发时,我们都会设置一个 1 秒(或 1,000 毫秒)的计时器,它将更新该时间过去后剩余的时间。

此后,循环将每秒继续。

为了帮助消除堆叠超时和导致错误的可能性,请在 useEffect 挂钩中添加 clearTimeout 方法。

添加一个 clearTimeout 方法并传入变量 timer 作为参数:

反应钩子定时器/src/App.js

// ...

useEffect(() => {
  const timer = setTimeout(() => {
    setTimeLeft(calculateTimeLeft());
  }, 1000);

  return () => clearTimeout(timer);
});

// ...

return 函数在每次 useEffect 运行 timer 时都会运行,除了组件的第一次运行,如果组件卸载,将清除超时。

现在您的状态已设置为 calculateTimeLeft() 对象并且正在您的效果挂钩内更新,它可以用于构建您的显示组件。

第 5 步 — 使用 Object.keys

在此步骤中,您将使用 Object.keys 迭代 timeLeft 对象并构建一个显示组件。 您将使用显示组件来显示 Hacktoberfest 开始之前的剩余时间。

首先,在 useEffect 挂钩下创建一个名为 timerComponents 的新变量:

反应钩子定时器/src/App.js

// ...

const timerComponents = [];

// ...

遍历 timeLeft 中的键后,您将使用此变量在剩余时间内推送一个新的 JSX 组件

接下来,使用 Object.keys 迭代从 calculateTimeLeft 函数返回的 timeLeft 对象。

将此代码添加到 timerComponents 变量中:

反应钩子定时器/src/App.js

// ...

const timerComponents = [];

Object.keys(timeLeft).forEach((interval) => {
  if (!timeLeft[interval]) {
    return;
  }

  timerComponents.push(
    <span>
      {timeLeft[interval]} {interval}{" "}
    </span>
  );
});

// ...

此处代码循环遍历 timeLeft 对象的属性。 如果计时器间隔的值大于零,它会将一个元素添加到 timerComponents 数组。

注意: 代码中额外的{" "} 用于使显示剩余时间的间隔在屏幕上显示时不会相互冲突。

{} 允许您在 JSX 中使用 JavaScript,而 "" 添加空间。


现在您已准备好在 App components return 语句中添加新的 JSX,以显示距离 Hacktoberfest 还剩的时间。

第 6 步 — 显示剩余时间

在这一步中,您会将 JSX 组件添加到应用程序组件的 return 语句中。 您将使用三元运算符来检查是否还有时间或是否到了 Hacktoberfest,

要使用 timerComponents 数组,您需要检查它的长度并返回它或让用户知道计时器已经过去。

return 语句中添加以下代码:

反应钩子定时器/src/App.js

// ...

return (
  <div>
    {timerComponents.length ? timerComponents : <span>Time's up!</span>}
  </div>
);

// ...

在 React JSX 组件中,您使用三元运算符代替 JavaScript if 语句。 这是因为 JSX 中只允许使用表达式。

timerComponents.length 行代码检查 timerComponents 数组中是否有任何内容,如果有则渲染它,否则渲染 Time's up!

接下来,您将在 return 语句中再添加两个 JSX 组件,让用户知道他们在倒计时:

反应钩子定时器/src/App.js

// ...

return (
  <div>
    <h1>Hacktoberfest 2020 Countdown</h1>
    <h2>With React Hooks!</h2>
    {timerComponents.length ? timerComponents : <span>Time's up!</span>}
  </div>
);

// ...

要使用当前年份而不是硬编码 2020,您可以创建一个新的状态变量并将初始状态设置为 new Date().getFullYear();

在第一个 useState() 变量之后,添加以下代码:

反应钩子定时器/src/App.js

// ...

const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
const [year] = useState(new Date().getFullYear());

// ...

此方法将获取您在 calculateTimeLeft 函数中使用的当前年份。

然后,您可以从 h1 中删除硬编码的 2020 并将其替换为 year

反应钩子定时器/src/App.js

// ...

return (
  <div>
    <h1>Hacktoberfest {year} Countdown</h1>
    <h2>With React Hooks!</h2>
    {timerComponents.length ? timerComponents : <span>Time's up!</span>}
  </div>
);

// ...

这将显示您的状态变量,该变量现在将始终具有当前年份。 您完成的项目将如下所示:

查看此 GitHub 存储库 以查看完整代码。

结论

在本教程中,您使用 useStateuseEffect 挂钩构建了一个倒计时 UI 组件来管理和更新应用程序的状态。

从这里,您可以继续学习 样式化 React 组件 ,以创建更具吸引力的倒计时 UI。

您还可以在 DigitalOcean 上关注完整的 How To Code in React.js 系列,以了解有关使用 React 进行开发的更多信息。