📜 ⬆️ ⬇️

5 great ways to animate React applications in 2019



Animation in React applications is a popular and discussed topic. The fact is that there are many ways to create it. Some developers use CSS by adding tags to HTML classes. Great way, it's worth applying. But, if you want to work with complex types of animations, you should take the time to learn GreenSock, this is a popular and powerful platform. Also for creating animations there are lots of libraries and components. Let's talk about them.

The article discusses five ways to animate React applications:


Skillbox recommends: Online Profession Java Developer Educational Course.
We remind: for all readers of "Habr" - a discount of 10,000 rubles when writing to any Skillbox course on the promotional code "Habr".

All examples are available in the repository (hence the source code is inserted into the article instead of the pictures, as in the original article).
')

CSS


This method was mentioned at the very beginning, and it is really good. If, instead of importing JavaScript libraries, to use it, the build will be small, the browser does not need a lot of resources. And this, of course, affects application performance. If your animation should be relatively simple, pay attention to this method.

As an example, an animated menu:



It is relatively simple, with the CSS property and a trigger of type className = "is-nav-open" for the HTML tag.

You can use this method in different ways. For example, create a wrapper over the navigation, and then trigger field changes. Since navigation has a constant width of 250px, the width of the wrapper with the margin-left or translateX property must be the same width. If you need to show navigation, you need to add className = "is-nav-open" for the wrapper and move the wrapper to margin-left / translateX: 0 ;.

In the end, the source of the animation will look like this:

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> ); } } 

Here are the CSS styles:

 .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; } 

I repeat, if the animation is relatively simple, then this method is the main one. Users will appreciate the speed of the browser.

ReactTransitionGroup


The ReactTransitionGroup component was developed by the ReactJS community team. With it, you can easily implement the basic CSS-animations and transitions.

ReactTransitionGroup is designed to change classes when a component's life cycle changes. It has a small size, it needs to be installed in the package for the React-application, which slightly increases the overall size of the assembly. In addition, you can use the CDN.

ReactTransitionGroup has three elements, it is Transition, CSSTransition and TransitionGroup. To start the animation in them you need to wrap the component. Style, in turn, need to register in the CSS classes.

Here is the animation, and then - the way to implement it.



The first step is to import the CSSTransitionGroup from the react-transition-group. After that, you need to wrap the list and set the transitionName property. Each time a child item is added or removed in a CSSTransitionGroup, it receives animation styles.

 <CSSTransitionGroup transitionName="example"> {items} </CSSTransitionGroup> 

When setting the transitionName = "example" property, the classes in the style sheets must begin with the name of the 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; 

The above is an example of using ReactTransitionGroup.

We also need logic, with two methods for implementing the example of adding a list of contacts.

The first method is handleAdd — it adds new contacts, gets a random name, which it then places in the array state.items.

To remove a contact by index in the state.items array, 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> ); } }; 

React-animations


React-animations is a library that is built on animate.css. It's easy to work with her, she has a lot of different animation collections. The library is compatible with any inline-style library that supports the use of objects to define basic animation frames, including Radium, Aphrodite, or styled-components.



I know what you are thinking:



Now let's check how it works using the bounce animation as an example.



First, import the animation from react-animations.

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

Then, after creating the component, we wrap any HTML code or component to animate.

 <bounce><h1>Hello Animation Bounce</h1></bounce> 

Example:

 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> ); } } 

Everything works, the animation is very simple. In addition, there is a great solution for using bounce animation when scrolling - react-animate-on-scroll .

React-reveal


In the framework of React Reveal there are basic animations, including the gradual disappearance, reflection, scaling, rotation, and more. It gives you the opportunity to work with all the animations using props. So, you can set additional settings, including position, delay, distance, cascade and others. Other CSS effects can be used, including server rendering and high order components. In general, if you need a scroll animation, you should use this framework.

 import Fade from 'react-reveal/Fade'; <Fade top> <h1>Title</h1> </Fade> 



In total there are five blocks, each of them has a full-screen page and a title.

 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, }, }; 

Now we enter the constant animateList. The array includes five elements. After using the map array method, it is possible to render any element in the Fade components by inserting elements into the header. Styles that are defined in the styles constant get short CSS styles for both the block and the header. Above - five blocks with animation Fade.

TweenOne and animation in Ant Design


Ant Design - React UI-library, which contains a large number of useful and easy-to-use components. It is suitable if you need to create elegant user interfaces. Developed it in the company Alibaba, which uses the library in many of its projects.



In the example, quite a lot of animated components. Most of them have similar animation, so the implementation example will be simpler than the above. This will include only a ball, a green ball and an additional element, for example, a red square.



The animation uses the TweenOne component, which needs a PathPlugin to correctly set the motion path. It will only work if you put
PathPlugin in TweenOne.plugins.

 TweenOne.plugins.push(PathPlugin); 

The main parameters of the animation are as follows:


The last two parameters are very specific, but you should not worry about them, everything works as it should.

 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, }; 

Now you can start creating the object of animation.


 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, }, }; 

You also need to pay attention to the component TweenOne. All components will be imported from rc-tween-one. TweenOne is a basic component with basic proprs and animated props, which are animations. Each TweenOne has its own animation parameters, such as 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> ); } 



Yes, it looks scary, but the animation using this method is simple.

  <TweenOne component="g" animation={animate.redSquare} /> <TweenOne component="g" animation={animate.track} /> <TweenOne component="g" animation={animate.greenBall} /> 

All you need to do is to describe the animation rules and transfer them to the TweenOne component.

To achieve different goals need different approaches. In this article, several solutions were considered that can be used in a large number of projects. Your business is to choose the right one.
Skillbox recommends:

Source: https://habr.com/ru/post/456972/


All Articles