React урок 4 Сложные взаимодействия

Имея отлаженную функциональность, быстрое время загрузки и хорошую скорость работы, на сегодняшний день может быть не достаточным. Интерфейсы популярных проектов, становятся все более утонченными, добавляется анимация, перемещения элементов (drag and drop) и т.д. Что в целом можно назвать сложными взаимодействиями про них мы и поговорим в этой статье.

Анимация в React

React обеспечивает высокоуровневые инструменты для работы с анимацией на пример ReactCSSTransitionGroup (часть модуля дополнения). ReactCSSTransitionGroup это далеко не полный стек библиотеки анимации. Это функция интерполяции значений, управление временной шкалой или формирование цепочек. Все это работает при помощи CSS переходов (transitions) и анимации доступной в обычном браузере. Далее мы рассмотрим как использовать ReactCSSTransitionGroup для анимации компонентов.

CSS Анимация

Чтобы использовать ReactCSSTransitionGroup, вы должны быть знакомы с настройкой CSS переходов и анимации, вы должны знать, как вызвать их из JS. Давайте кратко рассмотрим эту тему. Прежде чем перейдем к применению этого добра к компонентам. Если вы уже все знаете, можете смело листать дальше, а кому интересно давайте продолжим.

Есть две категории анимаций в CSS: CSS переходы (transitions) и CSS ключевые кадры (keyframe).

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

CSS переходы

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

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

  • Имя свойства элемента для анимации (например, цвет или ширина). Если этот параметр опущен, в анимации будут участвовать все возможные свойства
  • Продолжительность анимации.
  • Опционально функция синхронизации для управления кривой ускорения.
  • Дополнительная задержка перед началом анимации.

Давайте создадим кнопку, которая будет изменять цвет фона при наведении курсора.

css_transitions_button

Примечание о префиксах

По состоянию на момент написания, некоторые WebKit-браузеры по прежнему требуют использовать префикса при использовании обоих видов анимации. Например для кнопки в предыдущем пример, надо добавить:

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

Ключевые кадры

Анимация на основе переходов обеспечивает контроль только надо началом и конечным состоянием. Все промежуточные шаги контролируются браузером. Анимация на основе ключевых кадров позволяет контролировать промежуточные шаги. Чтобы использовать ключевые кадры, надо указать все шаги анимации в отдельном блоке CSS, с правилом @keyframes и имя, например:

Это блок определяет набор основных кадров, с процентным соотношением позиции кадра.

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

Программный запуск CSS переходов и анимации

Давайте попробуем разобраться на примере бокового меню который будет запускаться по нажатию на кнопку в верхнем меню:

run_animations

Начнем с создания класса CSS определяющего стиль бокового меню:

Далее, создадим два класса с теми же свойствами и различными значениями. Первый класс (.sidebar-transition) устанавливает боковую панель прозрачной и за границами экрана, а второй (.sidebar-transition-active) делает ее видимой и позиционирует внутри границ экрана. Обратите внимание на то, что .sidebar-transition-active имеет свойство CSS перехода 0,5 секунд.

В HTML коде, боковая панель объявлена с .sidebar-transition, то есть по умолчанию скрыта:

Для примера мы не будем использовать React или другую библиотеку, а сделаем на простом JS, который не претендует на оптимальное решения. Все таки нам это надо только для демонстрации:

React CSSTransitionGroup

ReactCSSTransitionGroup простой элемент, который оборачивает все интересующие компоненты и добавляет к ним CSS анимацию и переходы в определенные моменты связанные с жизненным циклом компонента. ReactCSSTransitionGroup поставляется в качестве дополнения, так что не забудьте установить его с помощью npm install —save react-addons-css-transition-group.

Пример анимация в React: Список покупок

В качестве примера давайте создадим базовый список покупок с анимацией.

Основные настройки приложения

Для начала, создадим новый проект (можно воспользоваться шаблоном от сюда https://github.com/pro-react/react-app-boilerplate) и создадим новый главный файл AnimatedShoppingList.

Вот что он умеет:

  • при нажатии удаляет элемент из списка
  • добавление при помощи ввода в текстовое поле
  • так же для каждого элемента задан key.

Давайте добавим некоторые правила CSS, пока без анимации:

Добавление элемента ReactCSSTransitionGroup

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

Элементы ReactCSSTransitionGroup должны быть родительскими по отношению к элементам к которым вы хотите применить анимацию. Он будет принимает три реквизита: transitionName (название класса CSS, содержащее определение анимации), transitionEnterTimeout длительность анимации появления и transitionLeaveTimeout длительность анимации удаления в миллисекундах. В нашем примере вставлять в ReactCSSTransitionGroup будет обернут shoppingItems:

С этого момента, каждый раз, когда новый элемент добавляется в состояние, React будет добавлять к нему дополнительный CSS класс example-enter и example-enter-active на 300 миллисекунд, а затем удалит. Так же будет работать и удаление, только классы будут example-leave и example-leave-active соответственно. Давайте из добавим их:

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

Анимация появления

Уже имеющиеся в списке элементы появляются без анимации, давайте это исправим с помощью свойства transitionAppear компонента ReactCSSTransitionGroup:

И в CSS на надо добавить соответствующие классы:

Вот теперь список выезжает при загрузке страницы.

Drag and Drop

Drag & Drop (перемещение и падение) часто встречается в пользовательских интерфейсах и его реализация может быть сложной. В React есть библиотека которая предоставляет нам создавать подобные взаимодействия. Называется React DnD, будучи внешней библиотекой, что ее использовать нужно установить используя npm:

npm install –-save react-dnd@2.x.x react-dnd-html5-backend@1.x.x

Пример использования React DnD

Давайте создадим корзину покупок, товары будут представлять собой кружки, а корзиной будет прямоугольная область обведенная пунктиром, как на изображении ниже:

dndpng

Для этого создадим новый проект (надеюсь вы уже запомнили как это делать). Начнем с главного файла App:

Как видите мы добавили главный компонент Container про него и поговорим.

Container

Теперь давайте его создадим:

Обратите особое внимание на тот факт, что модуль экспортирует DragDropContext основанный на HTML5Backend и на нашем компоненте Container. На выходе получим Container, наделенный свойствами и методами для поддержки Drag & Drop. HTML5Backend — означает что для реализации Drag & Drop будет использоваться API HTML5 если он доступен, но есть и другие альтернативы Backend.

DragSource и DropTarget компоненты высшего порядка

Далее нам надо создать компоненты  Snack  и ShoppingCart, которые будут использовать DragSource и DropTarget. Оба компонента требуют некоторой настройки:

Type

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

Spec Object

Это просто объект JS описывающий поведение компонента при событиях перетаскивания.

Collecting Function

Эта функция дает нам контроль надо тем, как и какие реквизиты получает компонент.

ShoppingCart Component

Наш компонент ShoppingCart представляет простой div с белым фоном. И он должен реагировать на падение давайте добавим реакцию:

Теперь давайте добавим Collect function:

Все эти реквизиты будут использованы в функции render:

Snack Component

Styling

Канбан доска: Анимация и Drag & Drop

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

Анимация раскрытия Card

Для начало нам надо установить ReactCSSTransitionGroup:

npm i —save react-addons-css-transition-group

Теперь давайте импортируем и используем компонент ReactCSSTransitionGroup, а затем добавим необходимые css стили:

Перемещение Card

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

npm install —save react-dnd react-dnd-html5-backend

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

Обратите внимание у нас новый реквизит сardCallbacks, нам надо передать до компонента Card, начнем с  KanbanBoard:

А еще мы сейчас создадим файл constants.js, с таким содержимым:

Перемещение между столбцами

Давайте приступим с изменения компонента Card:

Теперь настало время подготовить списки:

И последнее надо изменить KanbanBoard:

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

Сортировка Card

Теперь давайте сделаем сортировку:

Вуаля! Теперь мы можем легко перемещать карточки.

Дроссельные обратные вызовы

Сейчас у нас при перемещении вызывается множество операций удаления добавление карточек и в следствии чего вызывается render очень много раз, что может быть проблемой производительности приложения. По этой причине давайте реализуем функцию дросселирования. Она получает два параметра, оригинальную функцию, которую вы хотите меньше вызывать и время ожидания, создадим ее в отдельном файле utils.js:

Теперь давайте ее используем:

 

Сохранение новой позиции и статуса карты

Первая мысль, чтобы реализовать сохранение на сервер — это использовать методы updateCardStatus и updateCardPosition. Но проблема здесь заключается в том, что во время перемещения карты, пользователь может навести на множество других карт и списков, прежде чем остановиться на конечном пункте назначения. Зачем сохранять промежуточные состояния перемещений? Плюс это усложнить реализацию отката в случае ошибки. И добавит не нужную нагрузку на сервер.

Стало быть нам надо сохранять только когда пользователь прекратил перетаскивание. Для этого мы создадим новый метод persistCardDrag, начнем с компонента KanbanBoardContainer:

Далее, все что нам нужно, это использоваться cardDragSpec в Card:

Итоги

Мы узнали как применить анимацию и Drag & Drop в React c использованием внешних библиотек.