介绍
在本教程中,您将创建一个倒数计时器。这个计时器将帮助你学习如何利用 React 钩子来更新状态和管理 React 组件中的副作用。
使用 React 钩子,您可以创建更清晰的代码、组件之间可重用的逻辑以及无需类即可更新状态。
倒数计时器是一个常见的 UI 组件,可以用于多种用途。他们可以向用户传达他们做某事的时间或距离某个事件发生的时间。您将在本教程中倒计时的事件是 DigitalOcean 的HacktoberFest。
在本教程结束时,您将拥有一个使用 ReactuseState()
和useEffect()
钩子的功能性且可重用的倒数计时器。
先决条件
在开始本指南之前,您需要具备以下条件:
- 你需要一个运行Node.js的开发环境;本教程在 Node.js 版本 10.20.1 和 npm 版本 6.14.4 上进行了测试。要在 macOS 或 Ubuntu 18.04 上安装它,请按照如何在 macOS 上安装 Node.js 和创建本地开发环境或如何在 Ubuntu 18.04 上安装 Node.js 的使用 PPA 安装部分中的步骤进行操作。
- 在本教程中,您将使用Create React App创建应用程序。您可以在如何使用 Create React App设置 React 项目中找到使用 Create React App 安装应用程序的说明
- 您还需要 JavaScript 的基本知识,您可以在How To Code in JavaScript 中找到这些知识,以及对 HTML 和 CSS 的基本了解。有关 HTML 和 CSS 的有用资源是Mozilla Developer Network。
第 1 步 – 创建一个空项目
在这一步中,您将使用Create React App创建一个新项目。然后,您将删除引导项目时安装的示例项目和相关文件。
首先,创建一个新项目。在您的终端中,运行以下脚本以使用以下命令安装新项目create-react-app
:
- npx create-react-app react-hooks-counter
项目完成后,切换到目录:
- cd react-hooks-counter
在新的终端选项卡或窗口中,使用Create React App start script启动项目。浏览器将自动刷新更改,因此在您工作时保持此脚本运行:
- npm start
您将获得一个本地运行的服务器。如果项目没有在浏览器窗口中打开,您可以使用http://localhost:3000/
. 如果您从远程服务器运行它,则地址将为.http://your_server_ip:3000
您的浏览器将加载一个简单的 React 应用程序,该应用程序包含在 Create React App 中:
您将构建一组全新的自定义组件,因此您需要先清除一些样板代码,以便您可以拥有一个空项目。
首先,src/App.js
在文本编辑器中打开。这是注入页面的根组件。所有组件将从这里开始。您可以App.js
在如何使用 Create React App 设置 React 项目中找到更多信息。
src/App.js
使用以下命令打开:
- nano 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;
删除该行import logo from './logo.svg';
。然后替换return
语句中的所有内容以返回一组空标签:<></>
。这将为您提供一个不返回任何内容的有效页面。最终代码将如下所示:
import React from 'react';
import './App.css';
function App() {
return <></>;
}
export default App;
保存并退出文本编辑器。
最后,删除徽标,因为您不会在此应用程序中使用它。在您工作时删除未使用的文件以避免混淆是一个很好的做法。
在终端窗口中输入以下命令:
- rm src/logo.svg
如果您查看浏览器,您将看到一个空白屏幕:
现在项目已设置,您可以创建您的第一个组件。
第 2 步 — 计算还剩多少时间
在这一步中,您将创建一个函数来计算当前日期和 HacktoberFest 第一天之间的剩余时间。
首先,设置一个名为 的函数calculateTimeLeft
:
const calculateTimeLeft = () => {};
接下来,在函数内部,您将使用 JavaScriptDate
对象来查找当前的year
.
创建一个名为的变量year
,该变量设置为 JavaScriptdate
方法Date.getFullYear()
。
在calculateTimeLeft
函数内添加以下代码:
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
}
注意:您可以使用 JavaScriptDate
对象来处理日期和时间。
该Date.getFullYear()
方法将获取当前年份。
您现在可以使用此变量来计算当前日期与 HacktoberFest 第一天之间的差异。
在calculateTimeLeft
函数内部和year
变量下方,添加一个名为 的新变量difference
。Date
使用以下代码将其设置为等于一个新对象:
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
const difference = +new Date(`10/01/${year}`) - +new Date();
}
+
新Date
对象的before是告诉 JavaScript 将对象强制转换为整数的简写,它为您提供对象的 Unix 时间戳,表示为自纪元以来的微秒。
为了保持代码的可重用性,您使用JavaScript 模板文字并添加year
变量以及 HacktoberFest 的月份和日期。HacktoberFest 于每年 10 月 1 日开始。当您使用year
变量代替硬编码年份时,您将始终拥有当前年份。
现在您计算了倒数计时器到期之前的总毫秒数,您需要将毫秒数转换为更友好和人类可读的内容。
步骤 3 — 格式化为天、小时、分钟和秒
在此步骤中,您将创建一个名为 的空对象timeLeft
,使用if
语句检查是否有剩余时间,并使用数学和模数 ( %
) 运算符计算总小时数、分钟数和秒数。最后,您将返回timeLeft
.
首先,创建名为的空对象timeLeft
,然后在if
语句中填充天、小时、分钟和秒。
在calculateTimeLeft
函数内部和difference
变量下方添加以下代码:
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
let difference = +new Date(`10/01/${year}`) - +new Date();
let timeLeft = {};
}
现在创建一个if
语句来比较difference
变量以查看它是否大于0
。
在calculateTimeLeft
函数内部和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
函数内部和if
语句下方添加此代码:
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
:
import React, { useEffect, useState } from "react";
这段代码告诉 React,你想使用 React 提供的这些特定的钩子和它们的功能。
为了使倒数计时器工作,您需要连接我们之前编写的剩余时间方法来更新状态:
在calculateTimeLeft
函数下方添加此代码:
...
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
...
这种 JavaScript 语法称为数组解构。
该useState
方法接受一个参数来设置初始状态,并返回一个包含当前状态的数组和一个设置状态的函数。
timeLeft
将携带我们的时间间隔对象,并为我们提供设置状态的方法。在组件加载时,该timeLeft
值设置为当前剩余时间值。
接下来,您将使用useEffect
钩子来处理组件副作用。
注:一个副作用是什么,影响功能范围之外的东西被执行。
在此解决方案中,您将使用钩子setTimeout
内部的方法useEffect
。当在钩子内部使用时setTimeout
,类似的setInterval
方法是常见的 React 模式useEffect
。
大多数异步行为,如setTimeout
React 中的方法,都是使用useEffect
和useState
钩子的组合定义的。
注意:您可以了解更多有关何时以及如何使用方法一样setTimeout
,并setInterval
在本节阵营文档。
在useState()
函数下方添加此代码:
...
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
});
...
这useEffect
是更新剩余时间的内容。默认情况下,React 会在每次渲染后重新调用效果。
每次timeLeft
在状态中更新变量时,都会useEffect
触发。每次触发时,我们都会设置一个 1 秒(或 1,000 毫秒)的计时器,它将更新该时间过后的剩余时间。
此后,该循环将每秒继续。
为了帮助消除堆栈超时和导致错误的可能性,您还应该clearTimeout
在useEffect
钩子中添加该方法。
添加一个clearTimeout
方法,传入变量timer作为参数:
useEffect(() => {
const timer=setTimeout(() => {
setTimeLeft(calculateTimeLeft());
setYear(new Date().getFullYear());
}, 1000);
// Clear timeout if the component is unmounted
return () => clearTimeout(timer);
});
该return
函数每次运行时都会useEffect
运行,timer
除了组件的第一次运行,如果组件被卸载,则会清除超时。
现在您的状态已设置为calculateTimeLeft()
对象并且正在您的效果挂钩内更新,它可以用于构建您的显示组件。
第 5 步 — 使用 Object.keys
在此步骤中,您将使用Object.keys
迭代timeLeft
对象并构建显示组件。您将使用显示组件显示 HacktoberFest 开始前的剩余时间。
首先,在useEffect
名为的钩子下创建一个新变量timerComponents
:
...
useEffect(() => {
setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
const timerComponents = [];
...
在迭代 中的键后timeLeft
,您将使用此变量在剩余时间推送一个新的JSX 组件。
接下来,用于Object.keys
迭代timeLeft
从calculateTimeLeft
函数返回的对象。
在timerComponents
变量中添加以下代码:
...
const timerComponents = [];
Object.keys(timeLeft).forEach((interval) => {
if (!timeLeft[interval]) {
return;
}
timerComponents.push(
<span>
{timeLeft[interval]} {interval}{" "}
</span>
);
});
<^>
...
这里的代码循环遍历timeLeft
对象的属性。如果计时器间隔的值大于零,则会向timerComponents
数组添加一个元素。
注意:{" "}
代码中的额外部分用于显示剩余时间的间隔在屏幕上显示时不会相互碰撞。
将{}
允许您使用JavaScript您的JSX内部和""
增加的空间。
现在您已准备好在 App componentsreturn
语句中添加新的 JSX以显示距离 HacktoberFest 的时间。
步骤 6 — 显示剩余时间
在此步骤中,您将向应用程序组件的return
语句中添加多个 JSX 组件。您将使用三元运算符来检查是否还有剩余时间或是否是 HacktoberFest 的时间,
要使用timerComponents
数组,您需要检查它的长度并返回它或让用户知道计时器已经过去。
在空return
语句中添加以下代码:
...
return (
<div>
{timerComponents.length ? timerComponents : <span>Time's up!</span>}
</div>
);
...
在 React JSX 组件中,您使用三元运算符代替 JavaScriptif
语句。这是因为 JSX 中只允许使用表达式。
这timerComponents.length
行代码检查timerComponents
数组中是否有任何内容,如果有则呈现它,否则呈现Time's up!
.
接下来,您将在return
语句中添加另外两个 JSX 组件,让用户知道他们正在倒计时:
...
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()
变量下方,添加以下代码:
...
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
<^>
const [year] = useState(new Date().getFullYear(););
<^>
...
此方法将像您在calculateTimeLeft
函数中使用的那样获取当前年份。
然后,您可以2020
从您的硬编码中删除h1
并将其替换为year
:
...
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 进行开发的更多信息。