react倒计时重新计时
介绍 (Introduction)
In this tutorial, you will create a countdown timer. This timer will help you learn how to leverage React hooks to update state and manage side effects in a React component.
在本教程中,您将创建一个倒数计时器。 这个计时器将帮助您学习如何利用React钩子来更新状态和管理React组件中的副作用。
With React hooks, you can create cleaner code, reusable logic between components, and update state without classes.
使用React钩子,您可以创建更简洁的代码,组件之间的可重用逻辑以及无需类即可更新状态。
Countdown timers are a common UI component and can serve many purposes. They can communicate to users how long they have been doing something or how much time until some event happens. The event you will countdown to in this tutorial is DigitalOcean’s HacktoberFest.
倒数计时器是常见的UI组件,可以用于多种用途。 他们可以向用户传达他们已经做了多长时间,或者直到某个事件发生之前需要花费多长时间。 您将在本教程中倒数的事件是DigitalOcean的HacktoberFest 。
By the end of this tutorial, you will have a functional and reusable Countdown timer using React’s useState()
and useEffect()
hooks.
在本教程结束时,您将使用React的useState()
和useEffect()
钩子来使用一个可重复使用的Countdown计时器。
先决条件 (Prerequisites)
Before you begin this guide, you’ll need the following:
在开始本指南之前,您需要满足以下条件:
You will need a development environment running Node.js; this tutorial was tested on Node.js version 10.20.1 and npm version 6.14.4. To install this on macOS or Ubuntu 18.04, follow the steps in How to Install Node.js and Create a Local Development Environment on macOS or the Installing Using a PPA section of How To Install Node.js on Ubuntu 18.04.
您将需要一个运行Node.js的开发环境; 本教程已在Node.js 10.20.1版和npm 6.14.4版上进行了测试。 要将其安装在macOS或Ubuntu 18.04上,请遵循如何在macOS上安装Node.js并创建本地开发环境中的步骤,或如何在Ubuntu 18.04上安装Node.js的 使用PPA安装部分中的步骤 。
In this tutorial, you will create apps with Create React App. You can find instructions for installing an application with Create React App at How To Set Up a React Project with Create React App
在本教程中,您将使用Create React App创建应用程序 。 您可以在如何使用Create React App 设置React项目中找到有关使用Create React App安装应用程序的说明。
You will also need basic knowledge of JavaScript, which you can find in How To Code in JavaScript, along with a basic understanding of HTML and CSS. A useful resource for HTML and CSS is the Mozilla Developer Network.
您还将需要JavaScript的基础知识,您可以在如何使用JavaScript进行编码中找到该知识,以及对HTML和CSS的基本理解。 Mozilla开发人员网络是HTML和CSS的有用资源。
第1步-创建一个空项目 (Step 1 — Creating an Empty Project)
In this step, you’ll create a new project using Create React App. Then you will delete the sample project and related files that are installed when you bootstrap the project.
在这一步中,您将使用Create React App创建一个新项目。 然后,您将删除示例项目以及在引导项目时安装的相关文件。
To start, make a new project. In your terminal, run the following script to install a fresh project using create-react-app
:
首先,创建一个新项目。 在您的终端中,运行以下脚本以使用create-react-app
安装新项目:
npx create-react-app react-hooks-counter
npx create-react-app react-hooks-counter
After the project is finished, change into the directory:
项目完成后,转到目录:
cd react-hooks-counter
cd react-hooks-counter
In a new terminal tab or window, start the project using the Create React App start script. The browser will auto-refresh on changes, so leave this script running while you work:
在新的终端标签或窗口中,使用Create React App启动脚本启动项目。 浏览器将自动刷新所做的更改,因此在工作时请保持此脚本运行:
- npm start npm开始
You will get a local running server. If the project did not open in a browser window, you can open it with http://localhost:3000/
. If you are running this from a remote server, the address will be http://your_server_ip:3000
.
您将获得本地正在运行的服务器。 如果未在浏览器窗口中打开项目,则可以使用http://localhost:3000/
打开它。 如果您是从远程服务器运行的,则该地址将为http:// your_server_ip :3000
。
Your browser will load with a simple React application included as part of Create React App:
您的浏览器将加载一个简单的React应用程序,该应用程序是Create React App的一部分:
You will be building a completely new set of custom components, so you’ll need to start by clearing out some boilerplate code so that you can have an empty project.
您将构建一套全新的自定义组件,因此您需要从清除一些样板代码开始,以便拥有一个空项目。
To start, open src/App.js
in a text editor. This is the root component that is injected into the page. All components will start from here. You can find more information about App.js
at How To Set Up a React Project with Create React App.
首先,在文本编辑器中打开src/App.js
这是注入页面的根组件。 所有组件将从此处开始。 您可以在如何使用创建React App设置React项目中找到有关App.js
更多信息。
Open src/App.js
with the following command:
使用以下命令打开src/App.js
:
- nano src/App.js 纳米src / App.js
You will see a file like this:
您将看到如下文件:
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;
Delete the line import logo from './logo.svg';
. Then replace everything in the return
statement to return a set of empty tags: <></>
. This will give you a valid page that returns nothing. The final code will look like this:
import logo from './logo.svg';
删除行import logo from './logo.svg';
。 然后替换return
语句中的所有内容以返回一组空标签: <></>
。 这将为您提供一个不返回任何内容的有效页面。 最终代码如下所示:
import React from 'react';
import './App.css';
function App() {
return <></>;
}
export default App;
Save and exit the text editor.
保存并退出文本编辑器。
Finally, delete the logo since you won’t be using it in this application. It’s a good practice to remove unused files as you work to avoid confusion.
最后,删除徽标,因为您将不在此应用程序中使用徽标。 最好在删除工作时删除未使用的文件,以免造成混乱。
In the terminal window type the following command:
在终端窗口中,输入以下命令:
- rm src/logo.svg rm src / logo.svg
If you look at your browser, you will see a blank screen:
如果您查看浏览器,将会看到一个空白屏幕:
Now that the project is set up, you can create your first component.
现在已经建立了项目,您可以创建第一个组件。
步骤2 —计算还剩下多少时间 (Step 2 — Calculating How Much Time is Left)
In this step, you will create a function that calculates the time remaining between the current date and the first day of HacktoberFest.
在此步骤中,您将创建一个函数,该函数计算当前日期与HacktoberFest的第一天之间的剩余时间。
First, set up a function called calculateTimeLeft
:
首先,设置一个名为calculateTimeLeft
的函数:
const calculateTimeLeft = () => {};
Next, inside the function, you will use the JavaScript Date
object to find the current year
.
接下来,在函数内部,您将使用JavaScript Date
对象查找当前year
。
Create a variable called year
that is set to the JavaScript date
method Date.getFullYear()
.
创建一个名为year
的变量,该变量设置为JavaScript date
方法Date.getFullYear()
。
Add the following code inside the calculateTimeLeft
function:
在calculateTimeLeft
函数内添加以下代码:
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
}
Note: You can use the JavaScript Date
object to work with dates and times.
注意:您可以使用JavaScript Date
对象处理日期和时间。
The Date.getFullYear()
method will grab the current year.
Date.getFullYear()
方法将获取当前年份。
You can now use this variable to calculate the difference between the current date and the first day of HacktoberFest.
现在,您可以使用此变量来计算当前日期与HacktoberFest第一天之间的差额。
Inside the calculateTimeLeft
function and below the year
variable, add a new variable called difference
. Set it equal to a new Date
object with the following code:
里面的calculateTimeLeft
功能及以下的year
变量,添加一个名为新变量difference
。 使用以下代码将其设置为新的Date
对象:
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
const difference = +new Date(`${year}-10-1`) - +new Date();
}
The +
before the new Date
object is shorthand to tell JavaScript to cast the object as an integer, which gives you the object’s Unix timestamp represented as microseconds since the epoch.
新Date
对象之前的+
是表示JavaScript将其强制转换为整数的简写形式,这为您提供了自epoch以来以毫秒为单位的Unix时间戳。
To keep the code reusable, you use a JavaScript Template Literal and add in the year
variable along with the month and day of HacktoberFest. HacktoberFest starts on October 1st each year. When you use the year
variable in place of a hard-coded year, you will always have the current year.
为了使代码可重复使用,您可以使用JavaScript模板文字,并添加year
变量以及HacktoberFest的月份和日期。 HacktoberFest于每年的10月1日开始。 当您使用year
变量代替硬编码的年份时,您将始终拥有当前年份。
Now that you calculated the total number of milliseconds until the countdown timer expires, you need to convert the number of milliseconds to something more friendly and human-readable.
现在您已经计算了倒数计时器到期之前的总毫秒数,您需要将毫秒数转换为更友好且更易理解的内容。
步骤3 —格式化为天,小时,分钟和秒 (Step 3 — Formatting to Days, Hours, Minutes, and Seconds)
In this step, you will create an empty object called timeLeft
, use an if
statement to check if there is time remaining, and calculate the total number of hours, minutes, and seconds by using math and the modulus (%
) operator. Finally, you will return the timeLeft
.
在此步骤中,您将创建一个名为timeLeft
的空对象,使用if
语句检查是否还有剩余时间,并通过使用数学和模数( %
)运算符来计算小时,分钟和秒的总数。 最后,您将返回timeLeft
。
First, create the empty object called timeLeft
which will then be filled in with days, hours, minutes, and seconds in the if
statement.
首先,创建一个名为timeLeft
的空对象,然后在if
语句中将其填充为天,小时,分钟和秒。
Add the following code inside the calculateTimeLeft
function and below the difference
variable:
将以下代码添加到calculateTimeLeft
函数内部,并在difference
变量下方:
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
let difference = +new Date(`${year}-10-1`) - +new Date();
let timeLeft = {};
}
Now create an if
statement that will compare the difference
variable to see if it is greater than 0
.
现在创建一个if
语句,它将比较difference
变量以查看它是否大于0
。
Add this code inside the calculateTimeLeft
function and below the timeLeft
variable:
将此代码添加到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)
};
}
...
In this code, you round the numbers from the day, hours, minutes, and seconds down and drop the remainder to get a whole number value. You can then compare the difference
to see if it is greater than 0
.
在此代码中,您将日期,小时,分钟和秒的数字四舍五入,然后减去其余部分以获得整数值。 然后,您可以比较difference
以查看其是否大于0
。
Finally, you need to return timeLeft
so that you can use the value elsewhere in the component.
最后,您需要返回timeLeft
以便可以在组件的其他位置使用该值。
Add this code inside the calculateTimeLeft
function and below the if
statement:
将此代码添加到calculateTimeLeft
函数内部以及if
语句下方:
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
let difference = +new Date(`${year}-10-1`) - +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;
}
Now that you have created a function that calculates the time left until Hacktoberfest, you can add in the app state that will control and update your timer.
现在,您已经创建了一个计算到Hacktoberfest剩余时间的函数,您可以添加应用状态来控制和更新计时器。
第4步-使用useState
和useEffect
更新您的应用程序状态 (Step 4 — Updating Your App State with useState
and useEffect
)
With React Hooks, you can add state management capabilities to existing functional components without converting them to a class. In this step, you will import the useState
and useEffect
hooks from React to manage state in this component.
使用React Hooks,您可以将状态管理功能添加到现有功能组件中,而无需将其转换为类。 在这一步中,您将从React导入useState
和useEffect
钩子以管理此组件中的状态。
At the top of the App.js
file, add useState
and useEffect
in your import statement:
在App.js
文件的顶部,在import语句中添加useState
和useEffect
:
import React, { useEffect, useState } from "react";
This code tells React that you want to use these specific hooks and their functionality that is available from React.
这段代码告诉React您想使用这些特定的钩子及其可从React获得的功能。
To make the countdown timer work, you will need to wire up the time remaining method we previously coded to update the state:
为了使倒数计时器正常工作,您需要连接先前编码的剩余时间方法以更新状态:
Add this code below the calculateTimeLeft
function:
将此代码添加到calculateTimeLeft
函数下面:
...
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
...
This JavaScript syntax is called array destructuring. The useState
method accepts a parameter to set the initial state and returns an array containing the current state and a function to set the state.
这种JavaScript语法称为数组解构 。 useState
方法接受用于设置初始状态的参数,并返回包含当前状态的数组和用于设置状态的函数。
timeLeft
will carry our time left object of intervals and provide us with a method to set the state. On component load, the timeLeft
value is set to the current time left value.
timeLeft
将携带间隔的剩余时间对象,并为我们提供一种设置状态的方法。 在组件加载时, timeLeft
值设置为当前剩余时间值。
Next, you will use the useEffect
hook to deal with the component side effects.
接下来,您将使用useEffect
挂钩处理组件的副作用。
Note: A side effect is anything that affects something outside the scope of the function being executed.
注意: 副作用是任何会影响正在执行的函数范围之外的内容的东西。
In this solution, you will use a setTimeout
method inside of the useEffect
hook. setTimeout
and the similar setInterval
method are common React patterns when used inside of the useEffect
hook.
在此解决方案中,您将在useEffect
挂钩内使用setTimeout
方法。 在useEffect
挂钩内使用setTimeout
和类似的setInterval
方法是常见的React模式。
Most async behaviors like the setTimeout
method in React are defined with a combination of the useEffect
and useState
hooks.
大多数异步行为(例如React中的setTimeout
方法)都是通过useEffect
和useState
挂钩的组合来定义的。
Note: You can read more about when and how to use methods like setTimeout
and setInterval
in this section of the React Docs.
注意:您可以在React Docs的这一部分中阅读有关何时以及如何使用诸如setTimeout
和setInterval
类的方法的更多信息。
Add this code below the useState()
function:
将此代码添加到useState()
函数下面:
...
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
});
...
The useEffect
is what updates the amount of time remaining. By default, React will re-invoke the effect after every render.
useEffect
是更新剩余时间量的内容。 默认情况下,React将在每次渲染后重新调用效果。
Every time the variable timeLeft
is updated in the state, the useEffect
fires. Every time that fires, we set a timer for 1 second (or 1,000ms), which will update the time left after that time has elapsed.
每次在状态中更新变量timeLeft
, useEffect
触发useEffect
。 每次触发时,我们都将计时器设置为1秒(或1,000毫秒),该计时器将更新经过该时间后的剩余时间。
The cycle will continue every second after that.
之后,该周期将每秒继续。
To help to eliminate the potential of stacking timeouts and causing an error you should add the clearTimeout
method inside the useEffect
hook as well.
为了帮助消除潜在的堆栈超时和引起错误,您还应该在useEffect
挂钩内添加clearTimeout
方法。
Add a clearTimeout
method and pass in the variable timer as a parameter:
添加clearTimeout
方法并将变量timer作为参数传递:
useEffect(() => {
const timer=setTimeout(() => {
setTimeLeft(calculateTimeLeft());
setYear(new Date().getFullYear());
}, 1000);
// Clear timeout if the component is unmounted
return () => clearTimeout(timer);
});
The return
function runs every time the useEffect
runs the timer
except for the first run of the component and will clear out the timeout if the component is unmounted.
return
函数在useEffect
运行timer
都运行,除了第一次运行组件时,如果卸载了组件,它将清除超时。
Now that your state is set to the calculateTimeLeft()
object and is updating inside your effect hook, it can be used to build your display component.
现在,您的状态已设置为calculateTimeLeft()
对象,并且在效果挂钩内部进行了更新,可以将其用于构建显示组件。
步骤5 —使用Object.keys
(Step 5 — Using Object.keys
)
In this step, you will use Object.keys
to iterate over the timeLeft
object and build out a display component. You will use the display component to show the time left before HacktoberFest begins.
在此步骤中,将使用Object.keys
遍历timeLeft
对象并构建一个显示组件。 您将使用显示组件显示HacktoberFest开始之前的剩余时间。
First, create a new variable under the useEffect
hook called timerComponents
:
首先,在useEffect
钩子下创建一个新的变量, useEffect
为timerComponents
:
...
useEffect(() => {
setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
const timerComponents = [];
...
After iterating over the keys in timeLeft
, you will use this variable to push a new JSX component with the time left.
在timeLeft
的键上进行迭代之后,您将使用此变量在剩余的时间内推送新的JSX组件 。
Next, use Object.keys
to iterate over the timeLeft
object you returned from your calculateTimeLeft
function.
接下来,使用Object.keys
遍历从calculateTimeLeft
函数返回的timeLeft
对象。
Add this code in the timerComponents
variable:
将此代码添加到timerComponents
变量中:
...
const timerComponents = [];
Object.keys(timeLeft).forEach((interval) => {
if (!timeLeft[interval]) {
return;
}
timerComponents.push(
<span>
{timeLeft[interval]} {interval}{" "}
</span>
);
});
<^>
...
Here the code loops through the properties of the timeLeft
object. If the timer interval has a value above zero, it adds an element to the timerComponents
array.
在这里,代码循环遍历timeLeft
对象的属性。 如果计时器间隔的值大于零,则会将一个元素添加到timerComponents
数组。
Note: The extra {" "}
in the code is used so that the intervals that display the time left do not run into each other when displayed on the screen.
注意:使用代码中多余的{" "}
,以便在屏幕上显示时,显示剩余时间的间隔不会相互冲突。
The {}
allow you to use JavaScript inside your JSX and the ""
add the space.
{}
允许您在JSX内使用JavaScript,而""
添加空格。
Now you are ready to add the new JSX in the App components return
statement to display the time left until HacktoberFest.
现在,您可以在App组件return
语句中添加新的JSX,以显示到HacktoberFest为止的剩余时间。
第6步-显示剩余时间 (Step 6 — Displaying the Time Left)
In this step, you will add several JSX components to the app component’s return
statement. You will use a ternary operator to check if there is time left or if it is time for HacktoberFest,
在此步骤中,您将向应用程序组件的return
语句中添加几个JSX组件。 您将使用三元运算符来检查是否还有剩余时间或是否是HacktoberFest的时间,
To use the timerComponents
array, you need to check its length and either return it or let the user know that the timer has already elapsed.
要使用timerComponents
数组,您需要检查其长度并返回它,或者让用户知道计时器已经过去。
Add this code inside the empty return
statement:
将此代码添加到空的return
语句中:
...
return (
<div>
{timerComponents.length ? timerComponents : <span>Time's up!</span>}
</div>
);
...
In React JSX components, you use a ternary operator in place of a JavaScript if
statement. This is because only expressions are allowed inside JSX.
在React JSX组件中,您使用三元运算符代替JavaScript if
语句。 这是因为JSX内仅允许使用表达式。
The timerComponents.length
line of code checks to see if there is anything inside the timerComponents
array and renders it if there is, otherwise it renders Time's up!
.
代码的timerComponents.length
行将检查timerComponents
数组中是否有任何内容,如果存在,则将其呈现,否则呈现Time's up!
。
Next, you will add two more JSX components to the return
statement to let the user know what they are counting down:
接下来,您将在return
语句中添加两个以上的JSX组件,以使用户知道它们正在递减的内容:
...
return (
<div>
<h1>HacktoberFest 2020 Countdown</h1>
<h2>With React Hooks!</h2>
{timerComponents.length ? timerComponents : <span>Time's up!</span>}
</div>
);
...
To use the current year instead of hard coding 2020
, you can create a new state variable and set the initial state to new Date().getFullYear();
.
要使用当前年份而不是硬编码2020
,可以创建一个新的状态变量并将初始状态设置为new Date().getFullYear();
。
Below the first useState()
variable, add this code:
在第一个useState()
变量下面,添加以下代码:
...
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
<^>
const [year] = useState(new Date().getFullYear(););
<^>
...
This method will grab the current year like you used in the calculateTimeLeft
function.
该方法将像在calculateTimeLeft
函数中一样使用当前年份。
You can then remove the hardcoded 2020
from your h1
and replace it with year
:
然后,您可以从h1
删除硬编码的2020
,并将其替换为year
:
...
return (
<div>
<h1>HacktoberFest {year}Countdown</h1>
<h2>With React Hooks!</h2>
{timerComponents.length ? timerComponents : <span>Time's up!</span>}
</div>
);
...
This will display your state variable, which will now always have the current year. Your completed project will look like this:
这将显示您的状态变量,现在将始终具有当前年份。 您完成的项目将如下所示:
Check out this GitHub repository to see the full code.
查看此GitHub存储库以查看完整代码。
结论 (Conclusion)
In this tutorial, you built a countdown UI component using the useState
and useEffect
hooks to manage and update your applications state.
在本教程中,您使用useState
和useEffect
挂钩构建了一个倒计时UI组件,以管理和更新您的应用程序状态。
From here, you can learn how to style React components to create a more attractive countdown UI.
从这里,您可以学习如何设置React组件的样式,以创建更具吸引力的倒计时UI。
You can also follow the full How To Code in React.js series on DigitalOcean to learn even more about developing with React.
您还可以在DigitalOcean上关注React.js中完整的“ 如何编写代码”系列,以了解有关使用React开发的更多信息。
翻译自: https://www.digitalocean.com/community/tutorials/react-countdown-timer-react-hooks
react倒计时重新计时