
La animaci贸n en las aplicaciones React es un tema popular y discutido. El hecho es que hay muchas formas de crearlo. Algunos desarrolladores usan CSS agregando etiquetas a las clases HTML. Gran manera, vale la pena usar. Pero, si desea trabajar con tipos complejos de animaciones, debe tomarse el tiempo para estudiar GreenSock, es una plataforma popular y poderosa. Tambi茅n hay muchas bibliotecas y componentes para crear animaciones. Hablemos de ellos.
Este art铆culo analiza cinco formas de animar aplicaciones React:
- CSS
- ReactTransitionGroup;
- Reaccionar animaciones
- Reaccionar-revelar;
- TweenOne y Ant Design.
Skillbox recomienda: El curso educativo en l铆nea "Profession Java-developer" .
Le recordamos: para todos los lectores de "Habr": un descuento de 10.000 rublos al registrarse en cualquier curso de Skillbox con el c贸digo de promoci贸n "Habr".
Todos los ejemplos est谩n disponibles en el
repositorio (desde aqu铆 las fuentes se insertan en el art铆culo en lugar de las im谩genes, como en el art铆culo original).
CSS
Este m茅todo fue mencionado al principio, y es realmente bueno. Si en lugar de importar bibliotecas de JavaScript y usarlo, el ensamblaje ser谩 peque帽o, el navegador no necesitar谩 muchos recursos. Y esto, por supuesto, afecta el rendimiento de la aplicaci贸n. Si su animaci贸n debe ser relativamente simple, preste atenci贸n a este m茅todo.
Un ejemplo es un men煤 animado:

Es relativamente simple, con una propiedad CSS y un disparador como className = "is-nav-open" para la etiqueta HTML.
Hay varias formas de usar este m茅todo. Por ejemplo, cree un contenedor sobre la navegaci贸n y luego invoque los cambios de campo. Como la navegaci贸n tiene un ancho constante de 250 px, el ancho del contenedor con la propiedad margin-left o translateX debe ser el mismo ancho. Si necesita mostrar la navegaci贸n, agregue className = "is-nav-open" para el contenedor y mueva el contenedor al margen izquierdo / translateX: 0;.
Finalmente, la fuente de animaci贸n se ver谩 as铆:
export default class ExampleCss extends Component { handleClick() { const wrapper = document.getElementById('wrapper'); wrapper.classList.toggle('is-nav-open') } render() { return ( <div id="wrapper" className="wrapper"> <div className="nav"> <icon className="nav__icon" type="menu-fold" onClick={() => this.handleClick()}/> <div className="nav__body"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Beatae ducimus est laudantium libero nam optio repellat sit unde voluptatum? </div> </div> </div> ); } }
Y aqu铆 est谩n los estilos 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; }
Repito, si la animaci贸n es relativamente simple, entonces este m茅todo es el principal. Los usuarios apreciar谩n el rendimiento del navegador.
ReactTransitionGroup
El componente ReactTransitionGroup fue desarrollado por el equipo de la comunidad ReactJS. Con 茅l, puede implementar f谩cilmente animaciones y transiciones CSS b谩sicas.
ReactTransitionGroup est谩 dise帽ado para cambiar las clases al cambiar el ciclo de vida del componente. Tiene un tama帽o peque帽o, debe instalarse en el paquete para la aplicaci贸n React, lo que aumentar谩 ligeramente el tama帽o general del ensamblaje. Adem谩s, puede usar CDN.
ReactTransitionGroup tiene tres elementos, estos son Transition, CSSTransition y TransitionGroup. Para comenzar la animaci贸n, debe envolver el componente en ellos. El estilo, a su vez, debe escribirse en clases CSS.
Aqu铆 est谩 la animaci贸n, y luego la forma de implementarla.

El primer paso es importar el CSSTransitionGroup desde react-transition-group. Despu茅s de eso, debe ajustar la lista y establecer la propiedad transitionName. Cada vez que agrega o elimina un elemento secundario en un CSSTransitionGroup, obtiene estilos animados.
<CSSTransitionGroup transitionName="example"> {items} </CSSTransitionGroup>
Al establecer la propiedad transitionName = "example", las clases en las hojas de estilo deben comenzar con el nombre del ejemplo.
.example-enter { 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;
Arriba hay un ejemplo usando ReactTransitionGroup.
Tambi茅n necesita l贸gica y dos m茅todos para implementar el ejemplo de agregar una lista de contactos.
El primer m茅todo handleAdd: agrega nuevos contactos, obtiene un nombre aleatorio, que luego coloca en la matriz state.items.
Para eliminar un contacto por 铆ndice en la matriz state.items, use 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) => ( <Item item={item} key={i} keyDelete={i} handleRemove={(i) => this.handleRemove(i)} /> )); return ( <Fragment> <Button onClick={this.handleAdd}/> <div className="project"> <CSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300} > {items} </CSSTransitionGroup> </div> </Fragment> ); } };
Reaccionar animaciones
React-animations es una biblioteca que se basa en animate.css. Es f谩cil trabajar con ella, tiene muchas colecciones de animaci贸n diferentes. La biblioteca es compatible con cualquier biblioteca de estilo en l铆nea que admita el uso de objetos para definir los cuadros principales de una animaci贸n, incluidos Radium, Afrodita o componentes con estilo.

S茅 lo que piensas:

Ahora veamos c贸mo funciona esto con el ejemplo de una animaci贸n de rebote.

Primero, importe la animaci贸n desde las animaciones de reacci贸n.
const Bounce = styled.div`animation: 2s $ {keyframes` $ {bounce} `} infinite`;Luego, despu茅s de crear el componente, envolvemos cualquier c贸digo HTML o componente para la animaci贸n.
<bounce><h1>Hello Animation Bounce</h1></bounce>
Un ejemplo:
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 ( <Bounce><h1>Hello Animation Bounce</h1></bounce> ); } }
Todo funciona, la animaci贸n es muy simple. Adem谩s, hay una gran soluci贸n para usar la animaci贸n de rebote al desplazarse:
reaccionar-animar-en-desplazamiento .
Reaccionar-revelar
El marco React Reveal tiene animaciones b谩sicas, que incluyen desvanecimiento, reflexi贸n, escalado, rotaci贸n y m谩s. Permite trabajar con todas las animaciones usando accesorios. Por lo tanto, puede especificar configuraciones adicionales, incluyendo posici贸n, retraso, distancia, cascada y otros. Se pueden utilizar otros efectos CSS, incluidos la representaci贸n del lado del servidor y los componentes de alto orden. En general, si necesita animaci贸n de desplazamiento, debe usar este marco.
import Fade from 'react-reveal/Fade'; <Fade top> <h1>Title</h1> </Fade>

Hay cinco bloques en total, cada uno de ellos tiene una p谩gina de pantalla completa y un t铆tulo.
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 ( <Fragment> {animateList.map((item, key) => ( <div style={styles.block} key={key}> <Fade top> <h1 style={styles.title}>{`block ${item}`}</h1> </Fade> </div> ))} </Fragment> ); } } 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, }, };
Ahora presentamos la constante animateList. La matriz incluye cinco elementos. Despu茅s de usar el m茅todo de matriz de mapa, es posible representar cualquier elemento en los componentes de Fade insertando elementos en el encabezado. Los estilos que se definen en la constante de estilos obtienen estilos CSS cortos tanto para el bloque como para el encabezado. Arriba hay cinco bloques con animaci贸n Fade.
TweenOne y animaci贸n en Ant Design
Ant Design es una biblioteca React UI que contiene una gran cantidad de componentes 煤tiles y f谩ciles de usar. Es adecuado si necesita crear interfaces de usuario elegantes. Desarrollado por Alibaba, que utiliza la biblioteca en muchos de sus proyectos.

El ejemplo tiene bastantes componentes animados. La mayor铆a de ellos tienen animaciones similares, por lo que una implementaci贸n de ejemplo ser谩 m谩s simple que la anterior. Esto incluir谩 solo una bola, una bola verde y un elemento adicional, por ejemplo, un cuadrado rojo.

La animaci贸n utiliza el componente TweenOne, que necesita PathPlugin para establecer correctamente la trayectoria. Todo esto funcionar谩 solo si se coloca
PathPlugin en TweenOne.plugins.
TweenOne.plugins.push(PathPlugin);
Las principales opciones de animaci贸n son las siguientes:
- duraci贸n - tiempo de animaci贸n en ms;
- facilidad - suavidad de la animaci贸n;
- yoyo - cambio de movimiento hacia adelante y hacia atr谩s con cada repetici贸n;
- repetir: repetir la animaci贸n. Necesitas usar -1 para una animaci贸n sin fin;
- p - las coordenadas de la ruta para la animaci贸n;
- easePath: coordenadas de la ruta suave para la animaci贸n.
Los dos 煤ltimos par谩metros son muy espec铆ficos, pero no se preocupe por ellos, todo funciona como deber铆a.
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, };
Ahora puede comenzar a crear el objeto de animaci贸n.
- redSquare contiene los par谩metros del bucle m谩s la coordenada Y, la duraci贸n y el retraso.
- greenBall contiene la ruta con los par谩metros del objeto x, y - el valor de p. Adem谩s, la duraci贸n, la repetici贸n y la suavidad son una funci贸n de TweenOne.easing.path, que tiene dos par谩metros.
- camino - easyPath.
- lengthPixel es una curva que se divide en solo 400 secciones.
- track: un 贸valo con ejes, tiene estilos de ciclo y un par谩metro de rotaci贸n.
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, }, };
Tambi茅n debe prestar atenci贸n al componente TweenOne. Todos los componentes se importar谩n de rc-tween-one. TweenOne es un componente b谩sico con accesorios b谩sicos y accesorios animados, que son animaciones. Cada TweenOne tiene sus propios par谩metros de animaci贸n, como redSquare, track, greenBall.
import React from 'react'; import TweenOne from 'rc-tween-one'; export default function BannerImage() { return ( <div className="wrapper-ant-design"> <svg width="482px" height="500px" viewBox="0 0 482 500"> <defs> <path d="M151,55 C129.666667,62.6666667 116,74.3333333 110,90 C104,105.666667 103,118.5 107,128.5 L225.5,96 C219.833333,79 209.666667,67 195,60 C180.333333,53 165.666667,51.3333333 151,55 L137,0 L306.5,6.5 L306.5,156 L227,187.5 L61.5,191 C4.5,175 -12.6666667,147.833333 10,109.5 C32.6666667,71.1666667 75,34.6666667 137,0 L151,55 Z" id="mask" /> </defs> <g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd" transform="translate(0, 30)"> <g id="Group-13" transform="translate(0.000000, 41.000000)"> <TweenOne component="g" animation={animate.redSquare}> <rect stroke="#F5222D" strokeWidth="1.6" transform="translate(184.000000, 18.000000) rotate(8.000000) translate(-184.000000, -18.000000) " x="176.8" y="150.8" width="14.4" height="14.4" rx="3.6" /> </TweenOne> </g> <g id="Group-14" transform="translate(150.000000, 230.000000)"> <g id="Group-22" transform="translate(62.000000, 7.000000)"> <image id="cc4" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/FpKOqFadwoFFIZFExjaf.png" width="151px" height="234px" /> </g> <mask id="mask-2"> <use xlinkHref="#mask" fill="white" transform="translate(-42, -33)" /> </mask> <g mask="url(#mask-2)"> <TweenOne component="g" animation={animate.track} style={{ transformOrigin: '122.7px 58px' }}> <g transform="translate(-16, -52)"> <g transform="translate(16, 52)"> <path d="M83.1700911,35.9320015 C63.5256194,37.9279025 44.419492,43.1766434 25.8517088,51.6782243 C14.3939956,57.7126276 7.77167019,64.8449292 7.77167019,72.4866248 C7.77167019,94.1920145 61.1993389,111.787709 127.105708,111.787709 C193.012078,111.787709 246.439746,94.1920145 246.439746,72.4866248 C246.439746,55.2822262 212.872939,40.6598106 166.13127,35.3351955" id="line-s" stroke="#0D1A26" strokeWidth="1.35" strokeLinecap="round" transform="translate(127.105708, 73.561453) rotate(-16.000000) translate(-127.105708, -73.561453) " /> </g> <TweenOne component="g" animation={animate.greenBall}> <image alt="globe" id="id2" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/IauKICnGjGnotJBEyCRK.png" x="16" y="62" width="26px" height="26px" /> </TweenOne> </g> </TweenOne> </g> </g> </g> </svg> </div> ); }
7.77167019,64.8449292 7.77167019,72.4866248 C7.77167019,94.1920145 61.1993389,111.787709 127.105708,111.787709 C193.012078,111.787709 246.439746,94.1920145 246.439746 import React from 'react'; import TweenOne from 'rc-tween-one'; export default function BannerImage() { return ( <div className="wrapper-ant-design"> <svg width="482px" height="500px" viewBox="0 0 482 500"> <defs> <path d="M151,55 C129.666667,62.6666667 116,74.3333333 110,90 C104,105.666667 103,118.5 107,128.5 L225.5,96 C219.833333,79 209.666667,67 195,60 C180.333333,53 165.666667,51.3333333 151,55 L137,0 L306.5,6.5 L306.5,156 L227,187.5 L61.5,191 C4.5,175 -12.6666667,147.833333 10,109.5 C32.6666667,71.1666667 75,34.6666667 137,0 L151,55 Z" id="mask" /> </defs> <g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd" transform="translate(0, 30)"> <g id="Group-13" transform="translate(0.000000, 41.000000)"> <TweenOne component="g" animation={animate.redSquare}> <rect stroke="#F5222D" strokeWidth="1.6" transform="translate(184.000000, 18.000000) rotate(8.000000) translate(-184.000000, -18.000000) " x="176.8" y="150.8" width="14.4" height="14.4" rx="3.6" /> </TweenOne> </g> <g id="Group-14" transform="translate(150.000000, 230.000000)"> <g id="Group-22" transform="translate(62.000000, 7.000000)"> <image id="cc4" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/FpKOqFadwoFFIZFExjaf.png" width="151px" height="234px" /> </g> <mask id="mask-2"> <use xlinkHref="#mask" fill="white" transform="translate(-42, -33)" /> </mask> <g mask="url(#mask-2)"> <TweenOne component="g" animation={animate.track} style={{ transformOrigin: '122.7px 58px' }}> <g transform="translate(-16, -52)"> <g transform="translate(16, 52)"> <path d="M83.1700911,35.9320015 C63.5256194,37.9279025 44.419492,43.1766434 25.8517088,51.6782243 C14.3939956,57.7126276 7.77167019,64.8449292 7.77167019,72.4866248 C7.77167019,94.1920145 61.1993389,111.787709 127.105708,111.787709 C193.012078,111.787709 246.439746,94.1920145 246.439746,72.4866248 C246.439746,55.2822262 212.872939,40.6598106 166.13127,35.3351955" id="line-s" stroke="#0D1A26" strokeWidth="1.35" strokeLinecap="round" transform="translate(127.105708, 73.561453) rotate(-16.000000) translate(-127.105708, -73.561453) " /> </g> <TweenOne component="g" animation={animate.greenBall}> <image alt="globe" id="id2" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/IauKICnGjGnotJBEyCRK.png" x="16" y="62" width="26px" height="26px" /> </TweenOne> </g> </TweenOne> </g> </g> </g> </svg> </div> ); }

S铆, parece aterrador, pero la animaci贸n que usa este m茅todo es simple.
<TweenOne component="g" animation={animate.redSquare} /> <TweenOne component="g" animation={animate.track} /> <TweenOne component="g" animation={animate.greenBall} />
Todo lo que necesita hacer es describir las reglas de animaci贸n y transferirlas al componente TweenOne.
Para lograr diferentes objetivos, se necesitan diferentes enfoques. Este art铆culo examin贸 varias soluciones que pueden usarse en una gran cantidad de proyectos. Su negocio es elegir el correcto.
Skillbox recomienda: