Эй, сегодня мы собираемся создать секундомер, используя реакцию. Это будет простое фронтенд-приложение. Мы пройдем все этапы вместе.

Прежде всего, мы создадим приложение React, и для этого проекта я использую Visual Studio Code. Вы можете выбрать этот или любой другой редактор кода по вашему выбору.

Создайте приложение React:

Для этого зайдите в папку, в которую вы хотите сохранить этот проект. И откройте терминал там, и в терминале введите эту команду

секундомер npx create-react-app

Здесь npx — это команда, которая, по сути, является средством запуска пакетов, а create-react-app создает интерфейсную часть веб-приложения. Если вы хотите расширить его, вы можете подключить его к серверной части в будущем. Секундомер — это название приложения, которое мы создаем.

Вы увидите созданную папку с именем «Секундомер», в которой есть следующие папки и файлы. И если вы расширите папки public и src, вы заметите эти файлы внутри них.

Папка node_modules содержит все зависимости. Есть два файла: package.json и package-lock.json, которые содержат информацию о зависимостях проекта. Существует также файл README, в котором вы можете хранить информацию о своем проекте, чтобы дать другим возможность ознакомиться с ним. Внутри общей папки есть страница index.html, которая будет отображаться первой. А файл manifest.json описывает наше приложение (имя, автор и т. д.) и используется устройствами для быстрого доступа к этому приложению, если оно размещено на рабочем столе. robots.txt не позволяет сканерам и ботам поисковых систем сканировать наш сайт. Теперь удалите все файлы из папки src, кроме index.js. Также удалите файлы в общей папке, кроме index.html, manifest.json и robot.txt, и зайдите в файл manifest.json и удалите все ключи, связанные со значками.

В файле index.js

Внутри файла index.js удалите все, чтобы мы могли создать все с нуля. Во-первых, нам нужно импортировать react и react-dom. Для этого мы будем использовать следующие команды:

import React from 'react'
import ReactDOM from 'react-dom'

Теперь для рендеринга содержимого приложения мы будем использовать команду ReactDOM.render(), которая принимает 2 параметра. Первый параметр сообщает, что рендерить, а второй описывает, где рендерить. Если вы откроете файл index.html, вы увидите div с идентификатором root внутри тега body.

Итак, мы будем отображать наши компоненты внутри этого div с идентификатором root.

Следующий вопрос: какой компонент рендерить?

Мы визуализируем компонент приложения, который создадим позже, но сначала мы увидим команду для этого.

ReactDOM.render(<App />, document.getElementById("root"))

Итак, после всего этого наш файл index.js будет выглядеть так:

Создать компонент приложения

Внутри нашей папки src создайте еще одну папку с именем «components», в которой будут храниться компоненты, а внутри этой папки компонентов создайте 2 файла с именем «App»с расширениями «.js» и «. css» (чтобы эти файлы были App.js и App.css). Вы также можете поместить эти файлы в отдельную папку. Это полностью зависит от вас и от того, как вы хотите организовать свои папки и файлы. Поскольку у нас будет меньше компонентов, мы не будем создавать отдельную папку для каждого компонента.

В файле App.js

Импортируйте React из реакции, а также файл App.css с использованием компонента import ‘./App.css’.App, в котором будет храниться компонент секундомера, и мы сделаем его функциональным компонентом. Если вы хотите узнать об этом больше, вы можете прочитать об этом здесь. Итак, мы создадим функцию с именем Приложение с именем function App(){}, и внутри ее тела мы вернем div с именем класса контейнер, который будет иметь компонент секундомера. внутри него. Чтобы получить доступ к компоненту приложения, т. е. к этому файлу внутри файла index.js, нам нужно будет экспортировать этот файл, и это можно сделать с помощью export имя_функции по умолчанию, которое равно App, или это можно сделать и в одной строке, поместив export default перед function.

export default App

В файле App.js

Импортируйте React из реакции, а также файл App.css с использованием компонента import "./App.css". App, в котором будет храниться компонент секундомера, и мы сделаем его функциональным компонентом. Если вы хотите узнать об этом больше, вы можете прочитать об этом здесь. Итак, мы создадим функцию с именем App, которая будет function App(){}, и внутри ее тела мы вернем компонент секундомера внутри div с именем класса container. Чтобы получить доступ к компоненту приложения, то есть к этому файлу в файле index.js, нам нужно будет экспортировать этот файл, и это можно сделать с помощью export имя_функции по умолчанию, которое равно App . Это также можно сделать в одной строке, поместив export default перед function.

export default App

Кроме того, чтобы получить доступ к этому компоненту в index.js, нам придется импортировать этот файл внутрь index.js. Поэтому добавьте import App from './components/App' после импорта из реакции. Здесь «./components/App» — это относительное расположение приложения в индексе.

Создать компонент "Секундомер"

Внутри папки компонента снова создайте два файла с именами Stopwatch.js и Stopwatch.css, импортируйте файл React и stopwatch.css в файл stopwatch.js, создайте функцию с именем Stopwatch и экспортируйте ее. После всего этого импортируйте этот файл секундомера как «Секундомер» внутри компонента приложения, как мы делали ранее при создании компонента приложения.

В функции «Секундомер» мы вернем div с именем класса «секундомер» (мы добавили имя класса, чтобы можно было его стилизовать, но мы сделаем это позже). Внутри div секундомера мы создадим div таймера и кнопок div и у нас будет 3 кнопки, Старт/Стоп, Сброс и Пауза. Их функциональность соответствует их названию.

Давайте добавим эти кнопки, используя HTML-тег button, и поместим их в отдельный div с именем класса "buttons", который находится внутри div-блока секундомера.

function Stopwatch(){
  return (
    <div className="stopwatch">
        <div className="timer">
        </div>
        <div className="buttons">
          <button>Start</button>
          <button>Pause</button>
          <button>Reset</button>
</div>
    </div>
)
}

Теперь функциональность секундомера. Первоначально таймер должен быть установлен на 00.00.00, когда вы нажмете кнопку запуска, таймер должен запуститься, и он должен увеличивать значение таймера по мере прохождения времени, и он должен изменить свое имя, чтобы остановить и когда мы нажмем кнопку паузы, он должен приостановить таймер и изменить свое имя на возобновление, а когда мы нажмем кнопку остановки, он должен остановить таймер и снова изменить свое имя на запуск, а кнопка сброса должна сбросить таймер на 00.00. .00.

Итак, некоторые моменты, на которые следует обратить внимание:

  • Наше приложение ничего не делает после рендеринга, пока не будет нажата кнопка запуска, и нам нужно обновлять наш пользовательский интерфейс каждую секунду.
  • Кнопка паузы приостановит обновление пользовательского интерфейса, а при нажатии кнопки возобновления процесс обновления должен начаться с того места, где он был приостановлен.
  • Перезапуск должен сохранить все, как было в начале до нажатия кнопки «Пуск».

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

Итак, мы будем использовать хук состояния, чтобы сохранить значение между рендерами и запустить рендеринг после его обновления, что можно сделать с помощью:

const [seconds, setSeconds] = React.useState(0)

мы также можем сделать что-то вроде const [seconds, setSeconds] = useState(0)

Но для этого нам нужно импортировать его, поэтому мы можем просто добавить эту строку перед функцией секундомера import {useState} from React и все будет работать нормально. Эта строка импортирует хук состояния из модуля реакции, чтобы мы могли использовать его непосредственно в нашем коде (это называется деструктурированием объекта).

Хук состояния делает только две вещи:

  • Он сохраняет значение между рендерами, чтобы оно не потерялось.
  • Это дает вам функцию для обновления этого значения и запуска повторного рендеринга.

Здесь seconds сохраняет значение, setSeconds — это функция, которая обновит второе значение и вызовет повторный рендеринг, а 0 — это начальное значение секунд, которое мы ей дали. . Итак, добавьте эту строку перед оператором возврата внутри функции «Секундомер».

И мы знаем, что нам нужно обновить второе значение после нажатия кнопки запуска, поэтому для этого мы добавим еще одно состояние, которое будет увеличивать значение секунд каждую секунду. Это будет логическое значение с именем «isActive», и оно сообщит нашему приложению, работает ли таймер или нет. Если оно ложно, то таймер не будет работать, а если истинно, значит, таймер работает. и по умолчанию это будет ложь.

const [isActive, setIsActive] = React.useState(false)

Начать работу:

Теперь кнопка запуска должна запускать таймер, поэтому для этого нам нужно установить для isActive значение true при нажатии кнопки запуска. Для этого мы создадим функцию с именем «handleClick» (вы можете назвать ее как хотите) и изменим значение «isActive» с false на true.

function handleClick(){
  setIsActive(prevState => !prevState)
  if(!isActive)
        setSeconds(0)
}

Вы знаете, что кнопка запуска также является нашей кнопкой остановки, поэтому приведенный выше код гарантирует, что кнопка запуска изменит значение isActive с false на true и с true на false. Когда мы снова нажмем кнопку «Пуск», таймер должен начаться с 0.0.0. IsActive имеет значение true, когда таймер работает, поэтому, когда мы останавливаем таймер, isActive становится ложным, и мы устанавливаем состояние секунд равным 0.

setIsActive принимает в качестве параметра другую функцию (функция обратного вызова), которая принимает значение isActive и инвертирует его (другими словами, если значение isActive равно true, оно изменит его на false, и наоборот).

Чтобы кнопка запуска имела эту функцию и выполняла ее после нажатия, давайте добавим атрибут onClick и присвоим его значение {handleClick}. OnClick — это событие, которое происходит при щелчке элемента, для которого оно определено как атрибут, и выполняет функцию, назначенную в качестве его значения. И нам также нужно убедиться, что его значение изменилось после нажатия. Это также возможно в состоянии «Активно». Таким образом, когда isActive имеет значение false, что указывает на то, что таймер не работает, на кнопке должно быть написано «старт», а когда оно равно true, что указывает на то, что таймер работает, на кнопке должно быть написано «стоп». У нас есть логика; осталось только закодировать. Мы сделаем это с помощью тернарного оператора (?:).

<button onClick={handleClick}>{ isActive ? "Stop" : "Start" }</button>

Здесь мы добавили фигурные скобки ({}) между тегами кнопок, поскольку это позволяет добавлять код javascript между JSX (JSX позволяет нам писать HTML в React). Код между {} говорит, что если isActive имеет значение true, кнопка должна показывать Stop ; если оно ложно, должно отображаться Start.

Хм, теперь самый большой вопрос: как мы будем обновлять наш таймер каждую секунду? И как мы обеспечим, чтобы наше состояние секунд увеличивалось каждую секунду?

Для этого мы будем использовать setInterval с еще одним хуком под названием useEffect. setInterval позволяет нам запускать некоторый код через определенные промежутки времени. useEffect используется для обработки побочных эффектов, если таковые имеются. В двух словах, хук useEffect принимает функцию и массив в качестве параметров и запускает функцию всякий раз, когда изменяется значение любого элемента в массиве. Давайте сначала посмотрим на код:

React.useEffect(() => {
  let interval
  if(isActive){
      interval = setInterval(() => {
          setSeconds(prev => prev + 1)
      }, 1000)  
}
  
  return clearInterval(interval)
}, [isActive])

Когда мы нажмем кнопку запуска, состояние isActive будет истинным, и мы хотим, чтобы таймер начал работать, поэтому мы определим и инициализируем переменную interval в функции setInterval. . setInterval также принимает два параметра: во-первых, это функция (функция обратного вызова), которая должна запускаться через равные промежутки времени, а во-вторых, продолжительность интервала в миллисекундах (мс). Итак, после 1000 мс (1 сек = 1000 мс) мы хотим увеличить значение секунд. Для этого мы будем использовать функцию setSeconds в этой функции обратного вызова, которую мы объявили для обновления значения состояния секунд. Мы будем увеличивать секунды, взяв предыдущее значение секунд и добавив к нему +1.

Теперь второй параметр функции useEffect — это пустой массив. Подумайте: когда мы должны запускать и останавливать таймер? при нажатии кнопки запуска/остановки. isActive вначале имеет значение false, но при нажатии кнопки запуска isActive становится истинным, а при нажатии кнопки остановки isActive снова становится ложным. Таким образом, увеличение может зависеть от значения isActive. Таким образом, элемент массива будет иметь «isActive», потому что всякий раз, когда его значение изменяется, наша функция начинает выполняться или выполнение останавливается. Как же остановить этот рост?с помощью clearInterval. Итак, чтобы остановить интервал, мы используем clearinterval. Для этого мы вернем clearInterval с интервалом в качестве параметра.

Функция сброса:

И давайте поговорим о функции сброса тоже. Кнопка сброса устанавливает наш таймер на 00.00.00, что означает, что наше состояние секунд установлено на 0. Можете ли вы придумать способ сбросить состояние секунд на 0, когда мы нажимаем кнопку сброса? Если вы это сделали, что ж, отлично! Если вы не смогли, не волнуйтесь; мы пройдем через это вместе.

Хорошо, во-первых: изменение состояния секунд происходит после нажатия кнопки сброса, что означает, что нам нужно событие onClick, и мы меняем значение состояния, поэтому мы будем использовать setSeconds функция для обновления значения этого состояния. поэтому мы назначим onClick с помощью {handleResetClick} и создадим функцию с именем «handleResetClick()»перед оператором return. Внутри его тела мы передадим 0 в качестве параметра «setSeconds». После того, как мы нажмем кнопку сброса, состояние секунд будет сброшено на 0. Кроме того, мы устанавливаем для состояния isActive значение false, поэтому, если таймер находится в рабочем состоянии и нажата кнопка сброса, мы остановим таймер и установите его на 0.

function handleResetClick(){
  setSeconds(0)
  setIsActive(false)
}

//reset button changes
<button onClick = {handleResetClick} >Reset</button>

Пришло время таймера. Внутри блока «секундомер» мы создадим еще один блок с именем класса «таймер». Внутри этого div добавьте тег h1 со значением {seconds} между ними. Оно будет представлять второе значение таймера, а для минут и часов мы будем делать то, что мы делали на уроке математики: разделим секунды на 60 для минут и секунд на 3600 для часов. Есть еще одна вещь, о которой нам нужно позаботиться, то есть мы знаем, что у нас есть значения секунд и минут только до 60. Поэтому для этого мы будем использовать оператор по модулю (%).

<h1>{Maths.trunc((seconds/ 3600) % 24)} : {Maths.trunc((seconds/60) % 60)} : {Maths.trunc(seconds % 60)}</h1>
//         hours                                       minutes                          seconds

Поскольку секунды будут увеличиваться и будут пересекать 60 или любое число, кратное 60, seconds%60 снова начнется с 0 (поскольку модуль напоминает о секундах/60), а Math.trunc предназначен для получения только целого числа. ценности.

Функция приостановки:

Его функциональность такая же, как у кнопки остановки, за исключением того, что она не устанавливает значение состояния секунд в 0. Итак, если вы думаете, что мы можем просто переключить значение состояния «isActive», не внося никаких изменений в состояние «секунды», то с этим проблема, т.е. кнопка паузы не должна запускать таймер; эта кнопка должна работать только после того, как таймер находится в активном режиме, т. е. работает. и когда мы нажимаем кнопку паузы, когда таймер не работает, он устанавливает состояние isActive в true, что, в свою очередь, запускает таймер. Этого не должно быть, верно? Что, если есть состояние, позволяющее запускать и останавливать таймер только в том случае, если isActive имеет значение true (это наша функция паузы), т. е. только после нажатия кнопки запуска? Давайте создадим состояние isPaused с начальным значением false.

const [ isPaused, setIsPaused ] = React.useState(false)

Он должен иметь возможность запускать и останавливать таймер, а это означает, что он также влияет на setInterval, поэтому он также должен быть элементом второго параметра useEffect, массива (называемого массивом зависимостей).

Итак, вот обновленная версия хука useEffect.

 React.useEffect(() => {
        let interval
        if(isActive && !isPaused){
            interval = setInterval(() => {
                setSeconds(prev => prev + 1)
          }, 1000)
        }

      return () => clearInterval(interval)

    },[isActive, isPaused])

Здесь мы позволим увеличивать значение секунд только в том случае, если оно находится в активном состоянии и не приостановлено.

Добавьте атрибут onClick со значением «handlePause» в тег кнопки паузы и напишите функцию с именем handlePause(), которая при нажатии кнопки паузы устанавливает для «isPaused» значение true и меняет свое имя на «Resume», а когда щелкнул еще раз, устанавливает для isPaused значение false. Также есть условие if, которое проверяет, работает ли таймер. В этом случае можно будет изменить только состояние isPaused. Мы также увидим, истинно ли isPaused; если это так, на кнопке будет написано «Возобновить», если это не так, на ней будет написано «Пауза».

function handlePause(){
  if(isActive){
      setIsPause(prevState => !prevState)
  }
}

// Pause/Resume button

<button>{isPaused ? "Resume" : "Pause"}</button>

Или мы можем сделать всю эту кнопку паузы/возобновления видимой только во время работы таймера, используя состояние isActive. В нем говорится, что если таймер работает, покажите кнопку паузы; иначе ничего не показывать.

{ isActive ? <button onClick={handlePause}>{isPaused ? "Resume" : "Pause"}</button> : ""}

Вот код файла stopwatch.js:

Мы закончили с нашими функциями, поэтому, чтобы убедиться, что все функции работают нормально, сначала проверьте, находитесь ли вы в правильном каталоге, то есть внутри папки вашего проекта (для меня это папка секундомера). Если нет, войдите в это, используя cd «местоположение вашего проекта/имя_папки_проекта» (я был в каталоге проектов, где была моя папка секундомера, поэтому я сделал cd секундомер). Затем откройте командную строку и введите npm start в командной строке.

npm start запустит приложение на порту 3000. Для меня это порт 3000; если ваш порт уже используется, он может быть на другом порту для вас. И приложение будет выглядеть примерно так, когда оно работает в Chrome.

Это выглядит довольно скучно, поэтому мы сейчас его стилизуем. Итак, вот стили, которые я добавил в файл App.css (.container говорит, что внутри файла App.js есть класс с именем container.)

и стили, которые я добавил в Stopwatch.css:

После добавления стиля наше веб-приложение выглядит так. Это выглядит намного лучше, чем веб-приложение без стиля.

С этим, это обертка, ребята! Если вы достигли этого момента, большое спасибо за чтение этой статьи, и если она вам как-то помогла, дайте мне знать. Если есть какие-либо предложения или улучшения, это также высоко ценится и приветствуется.

Обратитесь к ним для справки: