Поиск по сайту:

Как создать таймер обратного отсчета с помощью 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:

  1. npx create-react-app react-hooks-timer

После завершения проекта перейдите в каталог:

  1. cd react-hooks-timer

В новой вкладке или окне терминала запустите проект с помощью сценария запуска Create React App. Браузер будет автоматически обновляться при изменениях, поэтому оставьте этот скрипт запущенным, пока вы работаете:

  1. 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 с помощью следующей команды:

  1. 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;.

Сохраните и выйдите из текстового редактора.

Наконец, удалите логотип, так как вы не будете использовать его в этом приложении. Хорошей практикой является удаление неиспользуемых файлов во время работы, чтобы избежать путаницы.

В окне терминала введите следующую команду:

  1. 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.