如何使用ReactHooks创建倒数计时器
介绍
在本教程中,您将使用 React 钩子创建倒数计时器,以更新状态并管理 React 组件中的副作用。
使用 React 钩子,您可以创建更简洁的代码、组件之间的可重用逻辑以及无需类即可更新状态。
倒数计时器是一个常见的 UI 组件。 他们可以与用户交流他们做某事的时间或距离某事件发生的时间。 您将在本教程中倒计时的活动是 DigitalOcean 的 Hacktoberfest。
在本教程结束时,您将拥有一个使用 React 的 useState()
和 useEffect()
钩子的功能性和可重用的倒计时计时器。
先决条件
在开始本指南之前,您需要以下内容:
- 您将需要一个运行 Node.js 的开发环境。 要在 macOS 或 Ubuntu 18.04 上安装它,请按照 如何在 macOS 上安装 Node.js 和创建本地开发环境中的步骤或 的 使用 PPA 部分安装如何在 Ubuntu 18.04 上安装 Node.js。
- 在本教程中,您将使用 Create React App 创建应用程序。 您可以在 How To Set Up a React Project with Create React App 找到使用 Create React App 安装应用程序的说明
- 您还需要 JavaScript 的基本知识,您可以在 如何在 JavaScript 中找到这些知识,以及对 HTML 和 CSS 的基本了解。 HTML 和 CSS 的一个有用资源是 Mozilla 开发者网络 。
本教程已使用 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 步 — 使用 useState
和 useEffect
更新您的应用程序状态
使用 React Hooks,您可以将状态管理功能添加到现有的功能组件中,而无需将它们转换为类。
在此步骤中,您将从 React 导入 useState
和 useEffect
挂钩以管理此组件中的状态。
在 App.js
文件的顶部,在导入语句中添加 useState
和 useEffect
:
反应钩子定时器/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
方法,都是使用 useEffect
和 useState
挂钩定义的。
注意: 您可以在 React Docs 的这一部分阅读更多关于何时以及如何使用 setTimeout
和 setInterval
等方法的信息。
在 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 存储库 以查看完整代码。
结论
在本教程中,您使用 useState
和 useEffect
挂钩构建了一个倒计时 UI 组件来管理和更新应用程序的状态。
从这里,您可以继续学习 样式化 React 组件 ,以创建更具吸引力的倒计时 UI。
您还可以在 DigitalOcean 上关注完整的 How To Code in React.js 系列,以了解有关使用 React 进行开发的更多信息。