Анимированный preloader на ReactJS. Используем Suspense

Анимированный preloader на ReactJS. Используем Suspense

Йо-йо! Я активно развиваю инструменты для работы с контентом. Недавно (август 2019) я перенёс часть инструментов на отдельный сайт и с ними вы можете познакомиться на сайте https://tools.xakplant.ru/. Этот сайт написан на react-js и представляет собой простое SPA. При переходе по страницам мне захотелось, чтобы появлялся preloader и я его сделал. Что получилось:

See the Pen xapl_preloader by xakplant (@xakplant) on CodePen.

Если вы читаете эту статью, значит вы не очень разбираетесь с реакте (как и я :D). Сделать preloader на реакте очень просто. Для этого в нём есть Suspense. Частично я уже затрагивал тему Suspens’a в статье про react-router-dom. Начнём же!

Создадим компонент

На вход suspense принимает html, строку или компонент. В моём примере будет компонент. Сначала у нас будет рендериться вот такой setup:

import React, { Component, Suspense, lazy } from 'react';
import Preloader from '../Preloader/Preloader';


export default class Cover extends Component{
    render(){
        return(
            <Preloader/>
        );
    }
}

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

Далее создаю по адресу «../Preloader/» файл Preloader.js. В нём у меня следующая разметка

import React, { Component } from 'react';
import './style.css';


export default class Preloader extends Component{
    render(){
        return(
            <div className="preloader">
                <div className="preloader__image_animate"></div>
            </div>
        );
    }

}

Ну и создаю в той же папке файл style.css и туда же кладу картинку с логотипом.

Написание стилей

Мой прелоадер состоит из двух блоков: фон и блок с логотипом, который вертится и слегка подпрыгивает.

Сначала я ввел пару переменных, чтобы мне было удобнее работать и не копировать код в последующем.

:root{
    --logo-size:80px;
    --logo-half-size:40px;
}

Далее я описал параметры блоков

.preloader{
    display: flex;
    width: 100%;
    height: 100vh;
    background: #222222;
    position: relative;
    transition: 0.5s;
}
.preloader__image_animate{
    background-image: url(./logo_white.svg);
    background-size: var(--logo-size) var(--logo-size);
    width: var(--logo-size);
    height: var(--logo-size);
    position: absolute;
    top: calc(50% - var(--logo-half-size));
    left: calc(50% - var(--logo-half-size));
    transition: 1s linear;
    animation: up-down 1s infinite; /* Название анимации up-down */
}

И описал анимацию

@keyframes up-down{
    0%{
        top: calc(50% - var(--logo-half-size));
    }
    0%{
        top: calc(50% - 10px);
    }
    75%{
        top: calc(50%); 
    }
    100%{
        top: calc(50% - 10px);
    }
    from{
        -webkit-transform: rotate(0deg);
        -o-transform: rotate(0deg);
        transform: rotate(0deg);
    }
    to{
        -webkit-transform: rotate(360deg);
        -o-transform: rotate(360deg);
        transform: rotate(360deg);
    }
}

From to в анимации я использовал для того, чтобы зациклить поворот на 360 градусов. Иначе логотип бы откручивался назад.

Для того, чтобы прелоадер пропадал перед появлением компонента, я немного изменил код:

import React, { Component } from 'react';
import './style.css';


export default class Preloader extends Component{
    constructor(props){
        super(props);
        this.viewRef = React.createRef();
    }
    render(){
        return(
            <div ref={this.viewRef} className="preloader">
                <div className="preloader__image_animate"></div>
            </div>
        );
    }

    componentWillUnmount(){
       this.viewRef.current.style.opacity = 0;
    }
}

Теперь перед демонтажем он становится прозрачным (в componentWillUnmount). Для этого мне понадобилось создать this.viewRef с помощью React.createRef() в конструкторе. Так я нашёл элемент в DOM, с которым мне нужно было произвести манипуляции.

Preloader готов!)

Ставим всё на свои места

Возвращаемся в наш файл, в котором рендериться компонент «Preloader» и используем suspense

import React, { Component, Suspense, lazy } from 'react';
import Preloader from '../Preloader/Preloader';
// Импортируем основной компонент
const MainArea = lazy(() => import('../MainArea/MainArea'));


export default class Cover extends Component{
    render(){
        return(
            // В fallback передаём preloder
            <Suspense fallback={<Preloader/>}>
                <MainArea />
            </Suspense>
        );
    }
}

Всё готово!

P.S.

Вы получили гайд по созданию preloader’а, а я создал новый сайт с инструментами для работы с контентом. Кстати, в нём есть отличный инструмент «Нормализация текста из КАПСА» . Думаю почти у каждого была нужда переделать текст из капса в нормальный текст. Теперь у вас есть инструмент, который быстро вернёт капсу человеческий вид и при этом сохранит первые буквы предложения заглавными. Переходите по ссылке https://tools.xakplant.ru/caps-normalize