Как создать таймер обратного отсчета с помощью React Hooks
Введение
В этом руководстве вы создадите таймер обратного отсчета, используя хуки React для обновления состояния и управления побочными эффектами в компоненте React.
С помощью хуков React вы можете создавать более чистый код, повторно используемую логику между компонентами и обновлять состояние без использования классов.
Таймеры обратного отсчета — распространенный компонент пользовательского интерфейса. Они могут сообщать пользователям, как долго они что-то делают или сколько времени осталось до того, как произойдет какое-то событие. Событие, до которого вы будете вести обратный отсчет в этом руководстве, — это Hacktoberfest DigitalOcean.
К концу этого руководства у вас будет функциональный и многоразовый таймер обратного отсчета, использующий хуки React useState()
и useEffect()
.
Предпосылки
Прежде чем приступить к работе с этим руководством, вам потребуется следующее:
- Вам потребуется среда разработки с запуском How To Install Node.js в Ubuntu 18.04.
- В этом руководстве вы создадите приложения с помощью Как настроить проект React с помощью Create React App
- Вам также потребуются базовые знания JavaScript, которые вы можете найти в сети разработчиков Mozilla.
Это руководство было проверено с помощью Node.js v16.13.1, npm
v8.2.0 и react
v17.0.2.
Шаг 1 — Создание пустого проекта
На этом этапе вы создадите новый проект, используя приложение Create React. Затем вы удалите пример проекта и связанные с ним файлы, которые устанавливаются при начальной загрузке проекта.
Для начала создайте новый проект. В терминале запустите следующий скрипт, чтобы установить новый проект с помощью 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
.
Ваш браузер загрузит приложение React, сгенерированное Create React App:
Вы будете создавать новый набор пользовательских компонентов, поэтому вам нужно будет начать с очистки некоторого шаблонного кода, чтобы у вас был пустой проект.
Для начала откройте src/App.js
в текстовом редакторе. Это корневой компонент, который внедряется на страницу. Все компоненты будут начинаться отсюда. Дополнительную информацию о App.js
можно найти в статье Как настроить проект React с помощью Create React App.
Откройте 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;
Затем замените все в операторе return
, чтобы вернуть набор тегов <div>
. Это даст вам действительную страницу, которая ничего не возвращает. Окончательный код будет выглядеть так:
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
:
// ...
const calculateTimeLeft = () => {
};
// ...
Далее внутри функции вы будете использовать объект JavaScript Date
, чтобы найти текущий год
.
Создайте переменную с именем year
, для которой задан метод JavaScript date
Date.getFullYear()
.
Добавьте следующий код внутрь функции calculateTimeLeft
:
// ...
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
}
// ...
Примечание. Вы можете использовать объект JavaScript Date
для работы с датами и временем.
Метод Date.getFullYear()
получит текущий год.
Теперь вы можете использовать эту переменную для расчета разницы между текущей датой и первым днем Hacktoberfest.
Внутри функции calculateTimeLeft
добавьте новую переменную с именем difference
. Установите его равным новому объекту Date
со следующим кодом:
// ...
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
const difference = +new Date(`10/01/${year}`) - +new Date();
}
// ...
Знак +
перед новым объектом Date
— это сокращение, указывающее JavaScript, что нужно преобразовать объект в целое число, что дает вам отметку времени Unix объекта, представленную в микросекундах с начала эпохи.
Примечание. Для этого руководства убедитесь, что дата, до которой вы ведете обратный отсчет, установлена в будущем, иначе вы столкнетесь с ошибкой.
Чтобы код можно было использовать повторно, вы используете литерал шаблона JavaScript и добавляете переменную year
вместе с месяцем и днем Hacktoberfest. Хактоберфест стартует 1 октября каждого года. Когда вы используете переменную year
вместо жестко заданного года, у вас всегда будет текущий год.
Теперь, когда вы подсчитали общее количество миллисекунд до истечения таймера обратного отсчета, вам нужно преобразовать количество миллисекунд во что-то более понятное и понятное человеку.
Шаг 3 — Форматирование в дни, часы, минуты и секунды
На этом шаге вы создадите пустой объект с именем timeLeft
, используете оператор if
, чтобы проверить, осталось ли время, и подсчитаете общее количество часов, минут и секунд с помощью математических операций и оператора модуля (%
). Наконец, вы вернете timeLeft
.
Сначала создайте пустой объект с именем timeLeft
, который затем будет заполнен днями, часами, минутами и секундами в операторе if
.
Добавьте следующий код внутрь функции calculateTimeLeft
:
// ...
const calculateTimeLeft = () => {
let year = new Date().getFullYear();
let difference = +new Date(`10/01/${year}`) - +new Date();
let timeLeft = {};
}
// ...
Теперь создайте оператор if
, который будет сравнивать переменную difference
, чтобы определить, больше ли она 0
.
Добавьте этот код в функцию calculateTimeLeft
:
// ...
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
:
// ...
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 вы можете добавлять возможности управления состоянием к существующим функциональным компонентам, не преобразовывая их в класс.
На этом шаге вы импортируете хуки useState
и useEffect
из React для управления состоянием в этом компоненте.
В начало файла 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
, в этом разделе документации React.
Добавьте этот код после функции useState()
:
// ...
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
});
// ...
useEffect
обновляет количество оставшегося времени. По умолчанию React повторно вызывает эффект после каждого рендеринга.
Каждый раз, когда переменная timeLeft
обновляется в состоянии, срабатывает useEffect
. Каждый раз, когда это срабатывает, мы устанавливаем таймер на 1 секунду (или 1000 мс), который будет обновлять время, оставшееся после истечения этого времени.
После этого цикл будет продолжаться каждую секунду.
Чтобы исключить возможность накопления тайм-аутов и возникновения ошибок, добавьте метод clearTimeout
внутрь хука useEffect
.
Добавьте метод clearTimeout
и передайте переменную timer в качестве параметра:
// ...
useEffect(() => {
const timer = setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
return () => clearTimeout(timer);
});
// ...
Функция return
запускается каждый раз, когда useEffect
запускает таймер
, за исключением первого запуска компонента, и сбрасывает тайм-аут, если компонент размонтированный.
Теперь, когда ваше состояние установлено на объект calculateTimeLeft()
и обновляется внутри вашего хука эффекта, его можно использовать для создания вашего компонента отображения.
Шаг 5 — Использование Object.keys
На этом шаге вы будете использовать Object.keys
для перебора объекта timeLeft
и создания компонента отображения. Вы будете использовать компонент отображения, чтобы показать время, оставшееся до начала Хактоберфеста.
Сначала создайте новую переменную под хуком useEffect
с именем timerComponents
:
// ...
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, а добавляет пробел.
Теперь вы готовы добавить новый JSX в оператор return
компонентов приложения, чтобы отобразить время, оставшееся до Hacktoberfest.
Шаг 6 — Отображение оставшегося времени
На этом шаге вы добавите компоненты JSX в оператор return
компонента приложения. Вы будете использовать тернарный оператор, чтобы проверить, осталось ли время или пришло ли время для Хактоберфеста,
Чтобы использовать массив timerComponents
, вам нужно проверить его длину и либо вернуть ее, либо сообщить пользователю, что таймер уже истек.
Добавьте этот код в оператор return
:
// ...
return (
<div>
{timerComponents.length ? timerComponents : <span>Time's up!</span>}
</div>
);
// ...
В компонентах React JSX вы используете тернарный оператор вместо инструкции JavaScript if
. Это связано с тем, что внутри JSX разрешены только выражения.
Строка кода timerComponents.length
проверяет, есть ли что-нибудь внутри массива timerComponents
, и отображает это, если есть, в противном случае — Times up!
.
Затем вы добавите еще два компонента JSX в оператор return
, чтобы пользователь знал, что он отсчитывает:
// ...
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
для управления и обновления состояния вашего приложения.
Отсюда вы можете продолжить обучение по стилизации компонентов React, чтобы создать более привлекательный пользовательский интерфейс с обратным отсчетом.
Вы также можете просмотреть полную серию How To Code in React.js на DigitalOcean, чтобы узнать еще больше о разработке с помощью React.