Translate

Поиск по этому блогу

Показаны сообщения с ярлыком слайдер. Показать все сообщения
Показаны сообщения с ярлыком слайдер. Показать все сообщения

понедельник, 13 мая 2019 г.

React-Сайт ( I ). Меню и слайдер.

Создадим полноценный сайт с меню, слайдером, обратным отчетом и прочими обычными и не очень компонентами



Что мы будем строить?

Лучше один раз увидеть , чем 100 раз услышать.

Готовый сайт на surge.sh


Все статьи этого проекта:




Начнем, как обычно с создания проекта на основе create-react-app. Если вы еще не знакомы с новой версией, то вам сюда ==> Что нового в приложении Create React App 3, а если не получилось запустить обновленную, третью версию, то вам сюда ==> cra3-boilerplate. Возмите готовое, настроенное мной решение и пользуйтесь в удовольствие.

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

Удаляем лишнее.

В папке src удаляем все кроме App.js index.js В файле index.js оставляем только то, что будем использовать:

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

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


В файле App.js оставляем только то, что будем использовать:

import React from "react";

function App() {
  return <div className="App">
              My App
         </div>;
}

export default App;


Добавляем нужное.

Папки-файлы

В папке src мы создадим папку resources, а в не папку слайд-фото для нашего слайдера - img. Вы можете взять любые три изображения размером 1920px x 1200px и сразу поместить их в эту папку.

В resources положим и файл для стилизации всего приложения - style.css Все стили для нашего приложения мы поместим в папку

Зависимости

Мы будем использовать Material-UI. Ранее я уже рассказывал о том. как использовать библиотеку Materialize. Позднее вы увидите. что они очень похожи и их использование не будет вызывать у вас беспокойства.

По поводу стилизации вашего приложения, я надеюсь, что на этом этапе вы можете сами написать нужные стили для вашего приложения и я на этом останавливаться не буду.

Итак. Мы будем использовать следующие модули:
  1. @material-ui/core
  2. @material-ui/icons
  3. react-reveal
  4. react-scroll
  5. react-slick
Устанавливаем material-ui

Ядро:

// with npm
npm install @material-ui/core

// with yarn
yarn add @material-ui/core



И иконки:

npm install @material-ui/icons


Одной командой:

npm install @material-ui/core @material-ui/icons


В файл App.js импортируем стили, которые создадим создадим в ранее созданном файле стилей и будем их добавлять к классам, которые мы будем присваивать нашим элементам разметки во всем приложении. Так можно поступить в данном случае, потому что у нас компонент App будет являться родителем для всего приложения. Само приложение будет небольшое, поэтому нет смысла использовать стороннюю библиотеку.

import './resources/styles.css';

Все компоненты мы будем помещать в отдельной папке. Создадим её - Components в папке src. В ней разу создадим папку для компонента Header с одноименным названием и в ней файл Header.js .

import React from "react";

const Header = () => {
  return <div>
          Header
         </div>;
};

export default Header;


И сразу импортируем и выведем его в App.js

import React from "react";
import './resources/style.css';
import Header from "./Compomemts/Header_Footer/Header";

function App() {
  return (
    <div className="App">
      <Header />
    </div>
  );
}

export default App;


Сейчас мы просто увидим слово Header на странице приложения.

Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Creating the main structure and connecting the header"
ci -m — здесь и далее - коммит.

Создание меню

Вывод логотипа и заголовка.

Импортируем в файл Header.js все необходимые для этого компоненты и создадим простую структуру на основе Material-UI.

Header.js
import React from "react";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";

const Header = () => {
  return (
    <AppBar
      position="fixed"
      style={{
        background: "#090050",
        padding: " 20px 0px"
      }}
    >
      <Toolbar>
        <div className="header_logo">
          <div className="font_left header_logo_title">wmg</div>
          <div className="font_left header_logo_caption">React mitting</div>
        </div>
      </Toolbar>
    </AppBar>
  );
};

export default Header;



Помимо инлайновых стилей, добавил немного и в resources/style.css

body {
    padding:0;
    margin:0;
    font-family: 'Roboto', sans-serif;
}

.font_left {
    font-family: 'Righteous', cursive;
}

/* ===============>>> HEADER <<<================ */
header {
    padding:10px 0px;
    transition: all 300ms ease-in;
}

header .header_logo {
    flex-grow: 1;
}
header .header_logo_title {
    text-transform: uppercase;
    font-size: 40px;
}

header .header_logo_caption {
    text-transform: uppercase;
}


Стили для шрифтов, я взял в Google Fonts и сразу же добавил их в header файла public/index.html В браузере пока что так:



Вывод значка сандвич меню.

Добавим вывод значка сандвич-меню в файл Header.js

import React from "react";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";

const Header = () => {
  return (
    <AppBar
      position="fixed"
      style={{
        background: "#090050",
        padding: " 20px 0px"
      }}
    >
      <Toolbar>
        <div className="header_logo">
          <div className="font_left header_logo_title">wmg</div>
          <div className="font_left header_logo_caption">React mitting</div>
        </div>
        <IconButton aria-label="Menu" color="inherit">
          <MenuIcon />
        </IconButton>
      </Toolbar>
    </AppBar>
  );
};

export default Header;



В браузере так:



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

Пока что мы просто добавим элементу

<IconButton aria-label="Menu" color="inherit" onClick={() => console.log("OPEN")} >

Если теперь посмотретьв браузере. то в консоли мы увидим "OPEN" при клике.

Идем в "Material-UI"==> "Component Demos"==> "Drawer". Здесь вы можете выбрать различные варианты для расположения сайтбара.

Оно определяется значение атрибута anchor="top" компонента Drawer. Атрибут open={this.state.top} получает значение из состояния компонента. Функция изменяет его и от того, true / false определяется показывать или нет меню-сайдбар.

Для сохранения порядка в нашем приложении, мы создадим в папке Header_Footer отдельный файл - SideDrawer.js

Внутри него определим обычный компонент без состояния (stateless component) и импортируем в него Driwer из Material-UI. Сразу же импортируем компонент List и ListItem оттуда же. Они нам потребуются для создания самого сайдбара с элементами.

Кстати, если вы используете VS-Code, то там есть отличный плагин - Reactjs code snippets, котоый позволяет писать компоненты одной короткой командой:
  • rcc - React Class Component
  • rsc - React Stateless Component
Компонент будет принимать props


import React from 'react';
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
const SideDrawer = () => {
  return (
    <Drawer
    anhor="right"
    open={}
    onClose={()=>{}}
    >
      Drawer
    </Drawer>
  );
};

export default SideDrawer;



В open мы в пропсах передадим состояние,и функцию закрытия. Пока что подключим наш файл в Header.js и добавим функцию, которую будем передавать вниз. Добавим состояние, используя hook - useState. Проще показать:

Header.js

import React, { useState } from "react";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";
import SideDrawer from "./SideDrawer";
const Header = () => {
  const [drawerOpen, setDrawerOpen] = useState(false);

  const toggleDrawer = value => {
    setDrawerOpen(value);
  };
  return (
    <AppBar
      position="fixed"
      style={{
        background: "#090050",
        padding: " 20px 0px"
      }}
    >
      <Toolbar>
        <div className="header_logo">
          <div className="font_left header_logo_title">wmg</div>
          <div className="font_left header_logo_caption">React mitting</div>
        </div>
        <IconButton
          aria-label="Menu"
          color="inherit"
          onClick={() => toggleDrawer(true)}
        >
          <MenuIcon />
        </IconButton>
        <SideDrawer open={drawerOpen} onClose={value => toggleDrawer(value)} />
      </Toolbar>
    </AppBar>
  );
};

export default Header;



И доделаем SideDrawer.js

import React from "react";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
const SideDrawer = props => {
  return (
    <Drawer
      anchor="right"
      open={props.open}
      onClose={() => props.onClose(false)}
    >
      Drawer
    </Drawer>
  );
};

export default SideDrawer;



Теперь по клику на сандвич показывается сайдбар.



Добавим разделы меню:

SideDrawer.js
import React from "react";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
const SideDrawer = props => {
  return (
    <Drawer
      anchor="right"
      open={props.open}
      onClose={() => props.onClose(false)}
    >
      <List component="nav">
        <ListItem button onClick={() => console.log("Start Events")}>
          Event starts in
        </ListItem>

        <ListItem button onClick={() => console.log("React info")}>
          React info
        </ListItem>

        <ListItem button onClick={() => console.log(" Our Team")}>
          Our Team
        </ListItem>

        <ListItem button onClick={() => console.log("Pricing")}>
          Pricing
        </ListItem>

        <ListItem button onClick={() => console.log("Location")}>
          Location
        </ListItem>
      </List>
    </Drawer>
  );
};

export default SideDrawer;



Стилизацию придает сама библиотека Material UI, в зависимости от заданных параметров листа и его итемов. Более подробно см в документации.

На клик в консоль, пока что просто вывел название элемента.

Теперь по клику мы сможем видеть наше меню, а в консоли будет пока что выводиться название раздела по которому кликнули.



Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Toggle Menu"

Добавление интерактивности меню.

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

App
import React from "react";
import "./resources/style.css";
import Header from "./Compomemts/Header_Footer/Header";

function App() {
  return (
    <div className="App" style={{ height: "2000px", background: "#BEE0FF"  }}>
      <Header />
    </div>
  );
}

export default App;



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

Добавим меню прозрачности при позиции без скрола - то есть в самом верхнем положении.

Для этого идем в файл Header.js и нам нужно добавить "состояние" нашему компоненту, которое будет отвечать за прозрачность меню (показать или нет меню полностью).

Сделаем это с помощью хука useState и зададим начальное состояние - false

const [headerShow, setHeaderShow] = useState(false);

Там, гдде мы задавали с вами цвет компоненту AppBar, внутри метода render(), мы добавим изменение цвета компонента по условию:

background: headerShow ? "#090050" : "transparent"

Сейчас все будет выглядеть так:



Уберем тень от меню - boxShadow: 'none'

Теперь наша задача изменить значение нашей переменной headerShow на true при скроле. Для этого мы будем использовать useEffect хук, который позволяет нам заменять жизненые циклы в компонентах без состояния.

Для этого нам нужно будет получить величину скрола. Это все просто, как в ванильном JS.

window.addEventLestener('scroll', handleScroll)

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

Теперь создадим стрелочную функцию handleScroll в которой будем изменять значение этого "состояния" в зависимости от данных скрола.

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
  }, [headerShow]);

  const handleScroll = () =>{
    if (window.scrollY > 0) {
      setHeaderShow(true)
    } else {
      setHeaderShow(false)
    }
  }


Эту функцию можно записать еще короче, тернарным оператором, но я оставлю ее здесь так, для наглядности.В коде можно записать и так:


  const handleScroll = () =>{
    (window.scrollY > 0) ? setHeaderShow(true) : setHeaderShow(false);
  }



И даже скобки не нужны, но... Мне вообще нравится тенденция использования коротких записей, только там, где это действительно необходимо, а не там, где хочется разработчику. Красота чтения такого кода, как книги, превосходит затраты на пару килобайт, компилированног кода. Всегда есть "золотая середина" и ее стоит придерживаться!

Теперь в браузере мы получим такую картину:



Вся красота создания таких компонентов в том, что они не только легкие, но еще и могут быть использованы как модули в других проектах. Они имеют свои независимые "состояния" и могут использоваться многократно со стилизацией под каждый отдельный проект.

Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Transparent Menu on Scroll events"

Слайдер

Переходим к слайдеру. В папке ресурсов, как мы и договорились ранее, есть папка с изображениями - img. все изображения имеют размер 1920 X 1200 px. Это позволит нам создавать слайдер на всю ширину окна браузера, без потери качества, в большинстве случаев.

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

В нижней части слайдера мы выведем калькулятор, который будет показывать оставшееся время (дни, часы, минуты, секунды) до намеченного события. Например - конференции React-разработчиков в Амстердаме.

Идем в проект и в папке Componentsи создадим там папку для нашего слайдера, заголовка и таймера - Sliderв ней файл index.js в который и будет собираться весь наш слайдер из трех вышеперечисленных компонентов.

Набираем - rsc и жмем Enter и у нас уже есть готовый функциональный компонент. переименовываем его в Slider. Не забываем изменить имя и в экспорте!

Всему возвращаемому элементу - div добавим стиль div style={{position:'relative'}}

Внутри него создадим два вложенных элемента в которых и будет находиться заголовок:

import React from "react";

const Slider = () => {
  return (
    <div style={{ position: "relative" }}>
      <div className="event_name">
        <div className="wrapper">React Meetting</div>
      </div>
    </div>
  );
};

export default Slider;



Импортируем все это в App.js и выводим на экран.

import React from "react";
import "./resources/style.css";
import Header from "./Compomemts/Header_Footer/Header";
import Slider from "./Compomemts/Slider";
function App() {
  return (
    <div className="App" style={{ height: "2000px", background: "#BEE0FF" }}>
      <Header />
      <Slider />
    </div>
  );
}

export default App;



На экране покажется заголовок, который мы вывели, справа, просто черным текстом. Добавим немного стилей в файле

src/resources/style.css
/* =================>>> SLIDER <<<================== */
.event_name {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 400px;
    height: 160px;
    -webkit-transform: translate(-50%, -50%);  
    transform: translate(-50%, -50%);   
    border: 2px solid white;
}

.event_name .wrapper {
    border: 2px solid white;
    height: 121px;
    margin: 6px;
    text-align: center;
    color: #fff;
    font-size: 40px;
    padding: 21px 70px 0px 70px;
    text-transform: uppercase;
}


Вы можете стилизовать все сами, как вам больше нравится.



Добавляем React-Slick

Прям там, на странице, мы возьмем cdn - ссылки для подключения css и добавим их в header нашего html - файла public/index.html

Там же на странице есть хорошие примеры подключения и использования слайдера. Добавляем его в проект:
npm install react-slick --save
Внутри папки Slider создадим файл Carousel.js, там так же создаем компонент без состояния. Импортируем сам слайдер import Slider from "react-slick"; В индексовый файл слайдера импортируем карусель: import Carousel from './Carousel'; И выводим ее на страницу перед заголовком. Возвращаемся в компонент Carousel и внутри компонента создадим константу с настройками слайдера.

    const settings = {
        dots: false,
        infinite:true,
        autoplay: true,
        speed: 500
    }


Думаю, что тут все и так понятно: dots - не показывать "точки" внизу слайдера, с бесконечной прокруткой, автоматический старт и задаем произвольно скорость.

Нашему оборачивающему диву добавим класс для стилизации и некоторые произвольные стили, которые я написал ниже.

src/resources/style.css
.carrousel_wrapper {
    height:700px;
    overflow: hidden;
}

.carrousel_image {
    
    background-size: cover !important;
}


Добавим ему и инлайновые стили

style={{
     height:`${window.innerHeight}px`,
     overflow:'hidden'
}}


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

Если сейчас прописать инлайн этому элементу какой либо другой цвет (например: background:'red'), то мы наглядно в этом убедимся.

Идем далее и по образцу на странице библиотеки слайдера, создадим компонент Slider внутри которого получим с помощью оператора rest - ... все настройки ...settings, как если бы мы их передали по отдельности так ( Slider dots: false infinite: true и т.д). Внутри него разместим наши слайды, которые импортируем в этот файл по отдельности из папки img. зададим им динамически высоту. А сами фото пойдут как фон дива. все очень очень просто!

Приведу этот файл полностью для наглядности.

Carousel.js
import React from "react";
import Slider from "react-slick";

import slide_one from "../../resources/img/slide_one.jpg";
import slide_two from "../../resources/img/slide_two.jpg";
import slide_three from "../../resources/img/slide_three.jpg";

const Carousel = () => {
  const settings = {
    dots: false,
    infinite: true,
    autoplay: true,
    speed: 500
  };
  return (
    <div
      className="carrousel_wrapper"
      style={{
        height: `${window.innerHeight}px`,
        overflow: "hidden"
      }}
    >
      <Slider {...settings}>
        <div>
          <div
            className="carrousel_image"
            style={{
              background: `url(${slide_one})`,
              height: `${window.innerHeight}px`
            }}
          />
        </div>
        <div>
          <div
            className="carrousel_image"
            style={{
              background: `url(${slide_two})`,
              height: `${window.innerHeight}px`
            }}
          />
        </div>
        <div>
          <div
            className="carrousel_image"
            style={{
              background: `url(${slide_three})`,
              height: `${window.innerHeight}px`
            }}
          />
        </div>
      </Slider>
    </div>
  );
};

export default Carousel;



Таким образом мы с вами получили слайдер, который сам запускается, занимает всю высоту экрана и меню, которое появляется только при начале скрола страницы.



Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Slider and Menu"

Обратный отсчет

Создаем сам таймер

Начнем с того, что в папке Slider создадим для этого компонента отдельный файл Timer.js c rsc (react stateless component). Сразу же импортируем его в Slider/index.js и выведем его сразу перед закрывающим последним дивом.

В компоненте Timer.js зададим общему диву класс для дальнейшей стилизации className="countdown_wrapper" Внутри него будут секции с днями, часами, минутами и секундами.

Внутри него создадим еще один див с заголовком события. Сразу после него еще один див с классом countdown_bottom и уже внутри него у нас будут 4 разных значения для вывода цифр.

Внутри него будет див с классом countdown_item, в который мы поместим еще два дива, один из которых будет для вывода значений - countdown_time, второй для вывода названия значения - countdown_tag.

Timer.js
import React from "react";

const Timer = () => {
  return (
    <div className="countdown_wrapper">
      <div className="countdown_top">Event starts in</div>
      <div className="countdown_bottom">
        <div className="countdown_item">
          <div className="countdown_time">15</div>
          <div className="countdown_tag">Days</div>
        </div>
      </div>
    </div>
  );
};

export default Timer;



В браузере пока что это выглядит очень неприглядно:



Добавим стили:

src/resources/style.css
/* =====================>>> TIMER <<<======================== */
.countdown_wrapper {
    position:absolute;
    bottom: 0px;
    color:#ffffff;
}

.countdown_wrapper .countdown_top {
    background: #ff4800;
    font-size: 19px;
    padding: 10px;
    display: inline-block;
    text-transform: uppercase;
}

.countdown_wrapper .countdown_bottom {
    display: flex;
    background: red;
    padding: 10px 20px;
}

.countdown_wrapper .countdown_time {
    font-size: 70px;
    border-right: 1px solid red;
    margin-right: 14px;
    padding-right: 49px;
}
.countdown_wrapper .countdown_item:last-child .countdown_time{
    border:none;
}

.countdown_wrapper .countdown_tag {
    text-transform: uppercase;
    font-size: 20px;
    padding-left: 7px;
}


Теперь так:



Идем в файл Timer.js.Теперь мы продублируем див с классом - countdown_item для того, чтобы на страницу выводились не только дни, но и часы, минуты и секунды.



Пока что так.

Добавляем эффект появления

Теперь мы добавим эффект появления нашего таймера при перезагрузке страницы.

Нам потребуется для этого - react-reveal

Отлично все написано на официальном сайте - react-reveal

Или на странице gitHub - github.com react-reveal

Согласно документации устанавливаем его.
npm install react-reveal --save


Здесь есть github.com react-reveal - примеры, которые вы можете смело использовать в ваших приложениях:

Теперь импортируем его в файл:

import Slide from 'react-reveal/Slide';

И обернем в него все что возвращает наш компонент (внутри return ()). Зададим ему параметры left delay={1000}

Таким образом у нас появился Fade эффект - плавного появления таймера справа.

Файл полностью:

Timer.js
import React from "react";
import Slide from "react-reveal/Slide";

const Timer = () => {
  return (
    <Slide left delay={1000}>
      <div className="countdown_wrapper">
        <div className="countdown_top">Event starts in</div>
        <div className="countdown_bottom">
          <div className="countdown_item">
            <div className="countdown_time">15</div>
            <div className="countdown_tag">Days</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">15</div>
            <div className="countdown_tag">Hs</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">15</div>
            <div className="countdown_tag">Min</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">15</div>
            <div className="countdown_tag">Sec</div>
          </div>
        </div>
      </div>
    </Slide>
  );
};

export default Timer;



Добавляем логику (динамическое изменение значений)

Мы создадим эту часть таким образом, чтобы в "состояния" (хуком) сохранить некую дату события и значения Дни, часы, минуты, секунды. Затем мы создадим функцию, которая будет считать сколько осталось дней, часов, минут, секунд до этой даты и эти значения заносила в наши "переменные состояния". Эту функцию мы будем вызывать каждую секунду, после загрузки нашего приложения, при помощи setInterval, а полученные значения мы будем передавать в компонент, где и отобразим их на странице. Это проще показать в коде.

Timer.js
import React, {useState, useEffect} from "react";
import Slide from "react-reveal/Slide";

const Timer = () => {
  const  deadline = 'Dec, 16, 2019';

  const [days, setDays] = useState('0');
  const [hours , setHours] = useState('0');
  const [minutes, setMinutes] = useState('0');
  const [seconds, setSeconds] = useState('0');

     const getTimeUntil = (deadline) =>{
        const time = Date.parse(deadline) - Date.parse(new Date());
        if(time < 0) {
            console.log('Date passed')
        } else {
            const seconds = Math.floor((time/1000)%60);
            const minutes = Math.floor((time/1000/60)%60);
            const hours = Math.floor((time/(1000*60*60))%24);
            const days = Math.floor(time/(1000*60*60*24));

          setDays(days);
          setHours(hours);
          setMinutes(minutes);
          setSeconds(seconds);
        }    
    }
    useEffect(()=>{
      setInterval(()=> getTimeUntil(deadline),1000)
    },[seconds])
  return (
    <Slide left delay={1000}>
      <div className="countdown_wrapper">
        <div className="countdown_top">Event starts in</div>
        <div className="countdown_bottom">
          <div className="countdown_item">
            <div className="countdown_time">{days}</div>
            <div className="countdown_tag">Days</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">{hours}</div>
            <div className="countdown_tag">Hs</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">{minutes}</div>
            <div className="countdown_tag">Min</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">{seconds}</div>
            <div className="countdown_tag">Sec</div>
          </div>
        </div>
      </div>
    </Slide>
  );
};

export default Timer;



Если посмотреть в браузер, то все "появляется и тикает". В итоге мы получили меню, которое меняется в зависимости от прокрутки, слайдер, который запускается автоматически и работает с определенным интервалом (кстати это не лишает возможности крутить его вручную мышкой), таймер, который плавно появляется при загрузке страницы и динамически отсчитывает время оставшееся до наступления события.



Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "TimerUntil event"



PS:
Иногда, бывают такие ситуации, что указывать deadline статически (присвоить постоянное значение) это не очень удобно. Я столкнулся с этим разместив этот учебный макет на surge. Время, в конце концов истекло и на сайте появились унылые нули.

Как исправить? Стоит задать deadline динамически, ну например, прибавлять к сегодняшней дате несколько дней. Я решил эту задачу очень просто - получил текущую дату, назначил новую и потом получил все данные новой даты deadline в нужном формате

Timer.js
import React, { useState, useEffect } from "react";
import Slide from "react-reveal/Slide";

const Timer = () => {
  let deadline = getDeadline();
  function getDeadline() {
    var D = new Date();
    D.setDate(D.getDate() + 50);

    var month = D.getMonth();

    function LitMonth(month) {
      switch (month) {
        case 0:
          month = "Jan";
          break;
        case 1:
          month = "Feb";
          break;
        case 2:
          month = "Mar";
          break;
        case 3:
          month = "Apr";
          break;
        case 4:
          month = "May";
          break;
        case 5:
          month = "Jun";
          break;
        case 6:
          month = "Jul";
          break;
        case 7:
          month = "Aug";
          break;
        case 8:
          month = "Sep";
          break;
        case 9:
          month = "Oct";
          break;
        case 10:
          month = "Nov";
          break;
        case 11:
          month = "Dec";
          break;

        default:
      }
      return month;
    }
    month = LitMonth(month);
    var day = D.getDate();
    var year = D.getFullYear();
    D = month + " " + day + " " + year;
    return D;
  }

  const [days, setDays] = useState("0");
  const [hours, setHours] = useState("0");
  const [minutes, setMinutes] = useState("0");
  const [seconds, setSeconds] = useState("0");

  const getTimeUntil = (deadline) => {
    const time = Date.parse(deadline) - Date.parse(new Date());
    if (time < 0) {
      console.log("Date passed");
    } else {
      const seconds = Math.floor((time / 1000) % 60);
      const minutes = Math.floor((time / 1000 / 60) % 60);
      const hours = Math.floor((time / (1000 * 60 * 60)) % 24);
      const days = Math.floor(time / (1000 * 60 * 60 * 24));

      setDays(days);
      setHours(hours);
      setMinutes(minutes);
      setSeconds(seconds);
    }
  };
  useEffect(() => {
    setInterval(() => getTimeUntil(deadline), 1000);
  }, [seconds]);
  return (
    <Slide left delay={1000}>
      <div className="countdown_wrapper">
        <div className="countdown_top">Event starts in</div>
        <div className="countdown_bottom">
          <div className="countdown_item">
            <div className="countdown_time">{days}</div>
            <div className="countdown_tag">Days</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">{hours}</div>
            <div className="countdown_tag">Hs</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">{minutes}</div>
            <div className="countdown_tag">Min</div>
          </div>
          <div className="countdown_item">
            <div className="countdown_time">{seconds}</div>
            <div className="countdown_tag">Sec</div>
          </div>
        </div>
      </div>
    </Slide>
  );
};

export default Timer;




Все что я добавил, выделено красным. Я думаю, что объяснять это не надо. С помощью библиотек, это можно было сделать проще и нагляднее, но мы решили идти по пути наименьшего использования сторонних ресурсов, поэтому так.

Все последние изменения вы можете посмотреть на gitHub react-site-slider-abc
ci -m "added dinamic deadline date"
                                                                                                                                                             

Телеграм канал - Full Stack JavaScript Developer


Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.Пишите мне - kolesnikovy70 почта gmail.com