[Перевод] 5 отличных способов анимировать React-приложения в 2019 году

4133784e6807b6e4f43c12b99d44b096.png

Анимация в приложениях React — популярная и обсуждаемая тема. Дело в том, что способов ее создания очень много. Некоторые разработчики используют CSS, добавляя теги в HTML-классы. Отличный способ, его стоит применять. Но, если вы хотите работать со сложными видами анимаций, стоит уделить время изучению GreenSock, это популярная и мощная платформа. Также для создания анимаций существует масса библиотек и компонентов. Давайте поговорим о них.
В статье рассматривается пять способов анимирования React-приложений:

  • CSS;
  • ReactTransitionGroup;
  • React-animations;
  • React-reveal;
  • TweenOne и Ant Design.


Skillbox рекомендует: Образовательный онлайн-курс «Профессия Java-разработчик».
Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».


Все примеры доступны в репозитории (отсюда в статью вставлены исходники вместо картинок, как в оригинальной статье).

CSS


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

В качестве примера — анимированное меню:
9ee0b68df5bea0e84028650227d399db.gif

Оно относительно простое, со свойством CSS и триггером типа className = «is-nav-open» для тега HTML.

Использовать этот метод можно разными способами. Например, создать над навигацией wrapper, а затем вызывать изменения полей. Поскольку навигация имеет постоянную ширину, которая равна 250 px, ширина wrapper со свойством margin-left или translateX должна иметь ту же ширину. При необходимости показать навигацию нужно добавить className = «is-nav-open» для wrapper и переместить wrapper на margin-left / translateX: 0;.

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

export default class ExampleCss extends Component {
    handleClick() {
        const wrapper = document.getElementById('wrapper');
        wrapper.classList.toggle('is-nav-open')
    }
    render() {
        return (
            
this.handleClick()}/>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Beatae ducimus est laudantium libero nam optio repellat sit unde voluptatum?
); } }


А вот CSS-стили:

.wrapper {
    display: flex;
    width: 100%;
    height: 100%;
    transition: margin .5s;
    margin: 0 0 0 -250px;
}
 
.wrapper.is-nav-open {
    margin-left: 0;
}
 
.nav {
    position: relative;
    width: 250px;
    height: 20px;
    padding: 20px;
    border-right: 1px solid #ccc;
}
.nav__icon {
    position: absolute;
    top: 0;
    right: -60px;
    padding: 20px;
    font-size: 20px;
    cursor: pointer;
    transition: color .3s;
}
 
.nav__icon:hover {
    color: #5eb2ff;
}


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

ReactTransitionGroup


Компонент ReactTransitionGroup разработала команда сообщества ReactJS. С его помощью можно без проблем реализовать основные CSS-анимации и переходы.

ReactTransitionGroup предназначен для изменения классов при изменении жизненного цикла компонента. У него небольшой размер, его нужно установить в пакете для React-приложения, что незначительно увеличит общий размер сборки. Кроме того, можно использовать и CDN.

У ReactTransitionGroup есть три элемента, это Transition, CSSTransition и TransitionGroup. Для запуска анимации в них нужно обернуть компонент. Стиль, в свою очередь, нужно прописывать в классах CSS.

Вот анимация, а дальше — способ ее реализации.

69675dcd02b16769f81e5f1ade6d14e9.gif

Первым делом нужно импортировать CSSTransitionGroup из react-transition-group. После этого требуется обернуть список и установить свойство transitionName. Каждый раз при добавлении или удалении дочернего элемента в CSSTransitionGroup он получает анимационные стили.


    {items}


При установке свойства transitionName = «example» классы в таблицах стилей должны начинаться с имени примера.

.example-eneter {
    opacity: 0.01;
}
 
.example-enter.example-enter-active {
    opacity: 1;
    transition: opacity 300ms ease-in;
}
 
.example-leave {
    opacity: 1;
}
 
.example-leave.example-leave-active {
    opacity: 0.01;
    transition: opacity 300ms ease-in;


Выше показан пример использования ReactTransitionGroup.

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

Первый метод handleAdd — он добавляет новые контакты, получает случайное имя, которое затем помещает в массив state.items.

Для удаления контакта по индексу в массиве state.items используется handleRemove.

import React, { Component, Fragment } from 'react';
import { CSSTransitionGroup } from 'react-transition-group'
import random from 'random-name'
import Button from './button'
import Item from './item'
import './style.css';
export default class ReactTransitionGroup extends Component {
    
    constructor(props) {
        super(props);
        this.state = { items: ['Natividad Steen']};
        this.handleAdd = this.handleAdd.bind(this);
    }
 
    handleAdd() {
        let newItems = this.state.items;
        newItems.push(random());
        this.setState({ items: newItems });
    }
 
    render () {
        const items = this.state.items.map((item, i) => (
             this.handleRemove(i)}
            />
        ));
 
    return (
        
            


React-animations


React-animations представляет собой библиотеку, которая построена на animate.css. С ней просто работать, у нее множество разных коллекций анимации. Библиотека совместима с любой inline-style-библиотекой, поддерживающей использование объектов для определения основных кадров анимации, включая Radium, Aphrodite или styled-components.

c20118d4c0c0a2dfeb354f375c2644b8.gif

Я знаю, что вы думаете:

a10023b92eb4d0285c1b5c7143ef4149.gif

Теперь проверим, как это работает на примере анимации подпрыгивания.

564dd851bad10642b69896f367932818.gif

Первым делом импортируем анимацию из react-animations.

const Bounce = styled.div`animation: 2s ${keyframes`${bounce}`} infinite`;

Затем, после создания компонента, оборачиваем любой HTML-код или компонент для анимации.

Hello Animation Bounce

Пример:

import React, { Component } from 'react';
import styled, { keyframes } from 'styled-components';
import { bounce } from 'react-animations';
import './style.css';
 
const Bounce = styled.div`animation: 2s ${keyframes`${bounce}`} infinite`;
 
export default class ReactAnimations extends Component {
    render() {
        return (
            

Hello Animation Bounce

); } }


Все работает, анимация очень простая. Кроме того, есть отличное решение для использования анимации подпрыгивания при прокрутке — react-animate-on-scroll.

React-reveal


Во фреймворке React Reveal есть основные анимации, включая постепенное исчезновение, отражение, масштабирование, вращение и другое. Он дает возможность работать со всеми анимациями при помощи props. Так, можно задавать дополнительные настройки, включая положение, задержку, расстояние, каскад и другие. Можно использовать и другие CSS-эффекты, включая серверный рендеринг и компоненты высокого порядка. В общем, если вам нужна анимация прокрутки, стоит использовать этот фреймворк.

import Fade from 'react-reveal/Fade';
 

    

Title

feb6b79efa6bfe5630b88b7318ca43e4.gif

Всего есть пять блоков, у каждого из них полноэкранная страница и заголовок.

import React, { Component, Fragment } from 'react';
import Fade from 'react-reveal/Fade';
 
const animateList = [1, 2, 3, 4, 5];
 
export default class ReactReveal extends Component {
    render() {
        return (
            
                {animateList.map((item, key) => (
                    

{`block ${item}`}

))}
); } } const styles = { block: { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', background: '#000', borderBottom: '1px solid rgba(255,255,255,.2)', }, title: { textAlign: 'center', fontSize: 100, color: '#fff', fontFamily: 'Lato, sans-serif', fontWeight: 100, }, };


Теперь вводим константу animateList. В массив включены пять элементов. После использования метода массива map есть возможность рендерить любой элемент в компонентах Fade, вставляя элементы в заголовок. Стили, которые определены в константе styles, получают короткие CSS-стили как для блока, так и для заголовка. Выше — пять блоков с анимацией Fade.

TweenOne и анимация в Ant Design


Ant Design — React UI-библиотека, которая содержит большое количество полезных и простых в использовании компонентов. Она подойдет, если вам нужно создавать элегантные пользовательские интерфейсы. Разработали ее в компании Alibaba, которая использует библиотеку во множестве своих проектов.

ffa4b8553cf31b046d79bc7ecace21b4.gif

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

6b023551e7558ef03020d2b79700acc8.gif

В анимации использован компонент TweenOne, которому нужен PathPlugin, чтобы правильно задать траекторию движения. Работать все это будет лишь в том случае, если поместить
PathPlugin в TweenOne.plugins.

TweenOne.plugins.push(PathPlugin);


Основными параметрами анимации являются следующие:

  • duration — время анимации в мс;
  • ease — плавность анимации;
  • yoyo — изменение движения вперёд и назад с при каждом повторении;
  • repeat — повтор анимации. Нужно использовать -1 для бесконечной анимации;
  • p — координаты пути для анимации;
  • easePath — координаты плавного пути для анимации.


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

const duration = 7000;
const ease = 'easeInOutSine';
const p =
  'M123.5,89.5 C148,82.5 239.5,48.5 230,17.5 C220.5,-13.5 127,6 99.5,13.5 C72,21 -9.5,56.5 1.5,84.5 C12.5,112.5 99,96.5 123.5,89.5 Z';
const easePath =
  'M0,100 C7.33333333,89 14.3333333,81.6666667 21,78 C25.3601456,75.6019199 29.8706084,72.9026327 33,70 C37.0478723,66.2454406 39.3980801,62.0758689 42.5,57 C48,46.5 61.5,32.5 70,28 C77.5,23.5 81.5,20 86.5,16 C89.8333333,13.3333333 94.3333333,8 100,0';
const loop = {
  yoyo: true,
  repeat: -1,
  duration,
  ease,
};


Теперь можно приступать к созданию объекта анимации.

  • redSquare содержит параметры цикла плюс координату Y, длительность и задержку.
  • greenBall содержит путь с параметрами объекта x, у — значение p. Кроме того, длительность, повтор и плавность — функция TweenOne.easing.path, у которой два параметра.
  • path — easePath.
  • lengthPixel — кривая, которая разделена всего на 400 секций.
  • track — овал с осями, у него есть стили цикла и параметр поворота.
const animate = {
  redSquare: {
    ...loop,
    y: 15,
    duration: 3000,
    delay: 200,
  },
  greenBall: {
    path: { x: p, y: p },
    duration: 5000,
    repeat: -1,
    ease: TweenOne.easing.path(easePath, { lengthPixel: 400 }),
  },
  track: {
    ...loop,
    rotate: 15,
  },
};


Также необходимо обратить внимание на компонент TweenOne. Все компоненты будут импортированы из rc-tween-one. TweenOne — базовый компонент с базовыми же proprs и анимационными props, которые и представляют собой анимацию. У каждого TweenOne — собственные параметры анимации, такие, как redSquare, track, greenBall.

import React from 'react';
import TweenOne from 'rc-tween-one';
 
export default function BannerImage() {
    return (
      
); }


ea1c6a322fac44bb9800cd0ce5d95f4b.gif

Да, выглядит страшновато, но анимация с использованием этого метода проста.

 
  
  


Требуется всего лишь описать правила анимации и перенести их в компонент TweenOne.

Для достижения разных целей нужны разные подходы. В этой статье были рассмотрены несколько решений, которые можно использовать в большом количестве проекта. Ваше дело — выбрать подходящее.

Skillbox рекомендует:

© Habrahabr.ru