There are several common animation implementations in React, and several react animation implementations

Source: Internet
Author: User
Tags image flip

There are several common animation implementations in React, and several react animation implementations

At present, users' requirements for front-end pages cannot meet the needs of functions, but they must be well-known and interesting. In addition to the overall UI appearance, adding appropriate animation effects in the right place is often more expressive than static pages to achieve more natural effects. For example, a simple loading animation or page switching effect can not only ease users' waiting mood, but also achieve brand promotion through brand logo and other forms.

As a Popular Front-end development framework in recent years, React puts forward the concept of virtual DOM. All DOM changes first occur on the virtual DOM and analyze the actual changes of web pages through DOM diff, then it is reflected in the real DOM, which greatly improves the web page performance. However, in terms of animation implementation, React, as a framework, does not directly provide animation effects to components and must be implemented by developers themselves. Most traditional web animations are implemented by directly operating actual DOM elements, this is obviously not promoted in React. So how can animation be implemented in React?

The essence of all animations is to continuously modify one or more attributes of DOM elements to produce a consistent effect of changes, thus forming an animation. In React, animation is essentially the same as traditional web Animation. There are still two ways to achieve it through css3 animation and modify element attributes through js. In actual implementation, the React framework features must be better met, which can be summarized into several categories:

  1. Interval Animation Based on timer or requestAnimationFrame (RAF;
  2. Simple animations Based on css3;
  3. CssTransitionGroup;
  4. Implement complex animation with hook;
  5. Other third-party animation libraries.
1. interval Animation Based on timer or RAF

At the earliest, animation implementation relied on timers.setInterval,setTimeoutOrrequestAnimationFrame(RAF) directly modify the attributes of the DOM element. Developers who are not familiar with the React feature may habitually passrefOrfindDOMNode()Get the real DOM node and directly modify its style. HoweverrefDirectly obtaining the real DOM and performing operations on it is not recommended. Avoid such operations as far as possible.

Therefore, we need to pass the timer, RAF, and other methods with the DOM node attributestateContact. First, you need to extract the attributes related to the change style and replace themstateAnd then add the timer orrequestAnimationFrameContinuous ModificationstateTo trigger component updates to achieve the animation effect.

Example

Take a progress bar as an example. The Code is as follows:

// Use requestAnimationFrame to change stateimport React, {Component} from 'react '; export default class Progress extends Component {constructor (props) {super (props); this. state = {percent: 10 };} increase = () => {const percent = this. state. percent; const targetPercent = percent> = 90? 100: percent + 10; const speed = (targetPercent-percent)/400; let start = null; const animate = timestamp => {if (! Start) start = timestamp; const progress = timestamp-start; const currentProgress = Math. min (parseInt (speed * progress + percent, 10), targetPercent); this. setState ({percent: currentProgress}); if (currentProgress <targetPercent) {window. requestAnimationFrame (animate) ;}}; window. requestAnimationFrame (animate);} decrease = () => {const percent = this. state. percent; const targetPercent = pe Rcent <10? 0: percent-10; const speed = (percent-targetPercent)/400; let start = null; const animate = timestamp => {if (! Start) start = timestamp; const progress = timestamp-start; const currentProgress = Math. max (parseInt (percent-speed * progress, 10), targetPercent); this. setState ({percent: currentProgress}); if (currentProgress> targetPercent) {window. requestAnimationFrame (animate) ;}}; window. requestAnimationFrame (animate);} render () {const {percent} = this. state; return (<div> <div className = "progress"> <div className = "progress-wrapper"> <div className = "progress-inner" style = {width: '$ {percent} %' }}> </div> <div className = "progress-info"> {percent }%</div> </div> <div className = "btns"> <button onClick = {this. decrease}>-</button> <button onClick = {this. increase >>+ </button> </div> );}}

In the exampleincreaseAnddecreaseBuild a linear transition function in the functionanimation,requestAnimationFrameExecute the transition function before each re-painting in the browser to calculate the current progress bar.widthAttribute and updatestateTo re-render the progress bar. The effect of this example is as follows:

This implementation method is in userequestAnimationFrameWhen the performance is good, it is completely implemented using pure js and does not rely on css. Frame freezing may occur when the timer is used. In addition, developers also need to calculate their own states based on the speed function, which is complicated.

2. Simple animations Based on css3

In css3animationAndtransitionAfter appearance and popularization, we can easily use css to change element styles without manually calculating real-time styles.

Example

The above progress bar is used as an example to implement the dynamic progress bar using css3. The Code is as follows:

Import React, {Component} from 'react '; export default class Progress extends Component {constructor (props) {super (props); this. state = {percent: 10 };} increase = () => {const percent = this. state. percent + 10; this. setState ({percent: percent> 100? 100: percent,})} decrease = () => {const percent = this. state. percent-10; this. setState ({percent: percent <0? 0: percent,})} render () {// same as above, omitted ....}}
. Progress-inner {transition: width 400 ms cubic-bezr (0.08, 0.82, 0.17, 1); // other styles are the same as above, omitted ...}

In the example,increaseAnddecreaseFunction is no longer computedwidth, But directly set the width after the increase or decrease. It should be noted thattransitionAttribute in the specifiedtransition-propertyWhen a style changes, the style changes dynamically and the speed curves of different speed effects can be set. The results of this example are shown in. Different from the previous example, the Progress data on the right side is directly changed to the target number without a specific change process, the dynamic effect of the progress bar is no longer linear, and the effect is more vivid.

The Implementation Method Based on css3 has a high performance and a small amount of code, but it only depends on the css effect and is difficult to implement complicated animations. In addition, by modifyingstateThe animation effect can only be applied to nodes that already exist in the DOM tree. If you want to add an entry and exit animation for the component in this way, you must maintain at least twostateTo achieve entry and exit animation, one of whichstateUsed to control whether the element is displayed.stateControls the changing attributes of an element in an animation. In this case, developers need to spend a lot of effort to maintain the animation logic of components, which is complex and cumbersome.

3. CssTransitionGroup, React animation plug-in

React has provided animation plug-ins for developers.react-addons-css-transition-groupAnd then handed over to the community for maintenance to form the currentreact-transition-groupThis plug-in allows you to easily implement the entry and exit animations of components. You need to install this plug-in an additional way.react-transition-groupIncludeCSSTransitionGroupAndTransitionGroupThe latter is the underlying api. The former is further encapsulated by the latter, making css animation easier.

Example

The code for dynamically adding a tab is as follows:

Import React, {Component} from 'react '; import {CSSTransitionGroup} from 'react-transition-group'; let uid = 2; export default class Tabs extends Component {constructor (props) {super (props); this. state = {activeId: 1, tabData: [{id: 1, panel: 'option 1'}, {id: 2, panel: 'option 2'}]};} addTab = () => {// Add the tab code ...} deleteTab = (id) = >{// Delete the tab code ...} render () {const {tabData, activeId} = This. state; const renderTabs = () => {return tabData. map (item, index) =>{ return (<div className = {'tab-item $ {item. id === activeId? 'Tab-item-activity': ''} '} key = {'tab $ {item. id} '}> {item. panel} <span className = "btns btn-delete" onClick = {() => this. deleteTab (item. id) }> cursor </span> </div> );})} return (<div> <div className = "tabs"> <CSSTransitionGroup transitionName = "tabs-wrap" transitionEnterTimeout = {500} transitionLeaveTimeout = {500}> {renderTabs ()} </CSSTransitionGroup> <span className = "btns btn-add" onClick = {this. addTab }>+ </span> </div> <div className = "tab-cont"> cont </div> );}}
/* Dynamically add an animation to the tab */. tabs-wrap-enter {opacity: 0.01 ;}. tabs-wrap-enter.tabs-wrap-enter-active {opacity: 1; transition: all 500 ms milliseconds-in ;}. tabs-wrap-leave {opacity: 1 ;}. tabs-wrap-leave.tabs-wrap-leave-active {opacity: 0.01; transition: all 500 ms latency-in ;}

CSSTransitionGroupYou can add additional css classes for its subnodes, and then use css animations to achieve entry and exit animations. To add animation effects to each tab node, you must first wrap them inCSSTransitionGroupComponent. When settransitionNameThe property is'tabs-wrapper',transitionEnterTimeoutAfter 400 milliseconds, onceCSSTransitionGroupThe newly added node will be added to the css class when it appears.'tabs-wrapper-enter'And then added the css class at the next frame.'tabs-wrapper-enter-active'. Because these two css classes have different transparency and css3 transition attributes, the node achieves the Entry Effect of transparency from small to large. 400 milliseconds later css class'tabs-wrapper-enter'And'tabs-wrapper-enter-active'Will be removed at the same time, and the node will complete the whole admission animation process. The implementation of the exit animation is similar to the entrance animation, except that the added css class is named'tabs-wrapper-leave'And'tabs-wrapper-leave-active'. Shows the effect of this example:

CSSTransitionGroupThe following seven attributes are supported:

The admission and departure animations are enabled by default and must be set during use.transitionEnterTimeoutAndtransitionLeaveTimeout. It is worth noting that,CSSTransitionGroupIt also provides an animation (appear) that needs to be set during use.transitionAppearTimeout. So what is the difference between an animation and an admission animation? When settransitionAppearIstrue,CSSTransitionGroupInFirst RenderingA stage is added. In this phase,CSSTransitionGroupExisting subnodes will be added to the css class one after another.'tabs-wrapper-appear'And'tabs-wrapper-appear-active'To achieve the animation effect. Therefore, an animation only appliesCSSTransitionGroupA subnode exists during the first rendering.CSSTransitionGroupAfter rendering is complete, its subnodes may only have an entry animation (enter) and an animation (appear ).

In additionCSSTransitionGroupNote the following:

  1. CSSTransitionGroupBy default,spanLabel packages its subnodes. If you want to use other html tags, you can setCSSTransitionGroupOfcomponentAttribute;
  2. CSSTransitionGroupMust be addedkeyWhen the node changes, the system accurately calculates which nodes need to be added with an entry animation and which nodes need to be added with an exit animation;
  3. CSSTransitionGroupThe animation effect is only applied to direct subnodes, but not to their child nodes;
  4. The animation end time is not based on the transition-duration in css,transitionEnterTimeout,transitionLeaveTimeout,TransitionAppearTimeoutIn some cases, the transitionend event is not triggered. For details, see MDN transitionend.

CSSTransitionGroupAdvantages of Animation:

  1. It is easy to use and allows you to conveniently and quickly implement the entry and exit animations of elements;
  2. Combined with React, the performance is better.

CSSTransitionGroupThe disadvantages are also obvious:

  1. Limited to animation, admission animation, and departure animation;
  2. Due to the need to developtransitionName, Insufficient flexibility;
  3. You can only rely on css for simple animation.
4. Complex animation with hook

In actual projects, some cool animation effects may be required. These effects are only dependent on css3 and are often difficult to implement. At this time, we may wish to use some mature third-party libraries, such as jQuery or GASP, combined with the lifecycle hook function in the React component to achieve complex animation effects. Except for the normal life cycle of the React component,CSSTransitionGroupUnderlying apiTransitonGroupIt also provides a series of special lifecycle hook functions for its child elements. These hook functions can be combined with a third-party animation library to achieve a wide range of entrance and departure animation effects.

TransisitonGroupThe following six lifecycle hook functions are provided:

  1. ComponentWillAppear (callback)
  2. ComponentDidAppear ()
  3. ComponentWillEnter (callback)
  4. ComponentDidEnter ()
  5. ComponentWillLeave (callback)
  6. ComponentDidLeave ()

Their triggering time:

Example

GASP is an animation library developed so far in the flash era. It draws on the concept of Video Frames and is especially suitable for the Series animation effect for a long time. In this article, we useTransitonGroupAndreact-gsap-enhancer(A gsap can be applied to the React enhancement Library) to complete an image gallery. The Code is as follows:

import React, { Component } from 'react'; import { TransitionGroup } from 'react-transition-group'; import GSAP from 'react-gsap-enhancer' import { TimelineMax, Back, Sine } from 'gsap';class Photo extends Component {   constructor(props) {    super(props);  }  componentWillEnter(callback) {    this.addAnimation(this.enterAnim, {callback: callback})  }  componentWillLeave(callback) {    this.addAnimation(this.leaveAnim, {callback: callback})  }  enterAnim = (utils) => {    const { id } = this.props;    return new TimelineMax()      .from(utils.target, 1, {        x: `+=${( 4 - id ) * 60}px`,        autoAlpha: 0,        onComplete: utils.options.callback,      }, id * 0.7);  }  leaveAnim = (utils) => {    const { id } = this.props;    return new TimelineMax()      .to(utils.target, 0.5, {        scale: 0,        ease: Sine.easeOut,        onComplete: utils.options.callback,      }, (4 - id) * 0.7);  }  render() {    const { url } = this.props;    return (      <div className="photo">              </div>    )  }}const WrappedPhoto = GSAP()(Photo);export default class Gallery extends Component {   constructor(props) {    super(props);    this.state = {      show: false,      photos: [{        id: 1,        url: 'http://img4.imgtn.bdimg.com/it/u=1032683424,3204785822&fm=214&gp=0.jpg'      }, {        id: 2,        url: 'http://imgtu.5011.net/uploads/content/20170323/7488001490262119.jpg'      }, {        id: 3,        url: 'http://tupian.enterdesk.com/2014/lxy/2014/12/03/18/10.jpg'      }, {        id: 4,        url: 'http://img4.imgtn.bdimg.com/it/u=360498760,1598118672&fm=27&gp=0.jpg'      }]    };  }  toggle = () => {    this.setState({      show: !this.state.show    })  }  render() {    const { show, photos } = this.state;    const renderPhotos = () => {      return photos.map((item, index) => {        return <WrappedPhoto id={item.id} url={item.url} key={`photo${item.id}`} />;      })    }    return (      <div>        <button onClick={this.toggle}>toggle</button>        <TransitionGroup component="div">          {show && renderPhotos()}        </TransitionGroup>      </div>    );  }}

In this examplePhotoOfcomponentWillEnterAndcomponentWillLeaveTwo hook functions add an admission animation for each child componententerAnimAnd departure AnimationLeaveAnim. In the admission animation, useTimeLineMax.from(target, duration, vars, delay)Method To create a timeline animation, specifying the animation movement distance of each sub-component alongidIncrease and decrease, and the delay time variesidThe extension time of each child component in the departure animation increasesidIncrease and decrease, so as to realizeidDifferent animations have different effects. You can add different effects to any sub-component as needed. Shows the effect of this example:

In useTransitionGroupIncomponentnWillAppear(callback),componentnWillEntercallback),componentnWillLeave(callback)The function must be called after the function logic ends.callbackTo guaranteeTransitionGroupCorrectly maintains the status sequence of sub-nodes.

Animation with hook can support a variety of complex animations, such as time series animations. Due to the dependency on third-party libraries, the animation effect is often smoother and the user experience is better. However, the introduction of third-party libraries requires developers to learn the corresponding APIs and improve Code complexity.

V. other third-party animation Libraries

There are also many excellent third-party animation libraries, such as react-motion, Animated, and velocity-react.

Animated

Animated is a cross-platform animation library that is compatible with React and React Native. In the animation process, we only care about the initial state, ending state, and changing functions of the animation, and do not care about the specific values of element attributes at each time point. Therefore, Animatied adopts a declarative animation, it provides a specific method for calculating css objects and passing inAnimated.divAnimation effect.

Example

We use Animated to implement the image flip effect. The Code is as follows.

Import React, {Component} from 'react '; import Animated from 'animated/lib/targets/react-dom'; export default class PhotoPreview extends Component {constructor (props) {super (props); this. state = {anim: new Animated. value (0) };} handleClick = () =>{ const {anim} = this. state; anim. stopAnimation (value => {Animated. spring (anim, {toValue: Math. round (value) + 1 }). start () ;}) ;}render () {const {anim} = this. state; const rotateDegree = anim. interpolate ({inputRange: [0, 4], outputRange: ['0deg ', '360deg']}); return (<div> <button onClick = {this. handleClick}> flip right </button> <Animated. div style = {transform: [{rotate: rotateDegree}]} className = "preivew-wrapper">  </Animated. div ></ div> );}}

In this example, we want to rotate the image 90 ° to the right after each button is clicked. A new value of 0 is created during component initialization.AnimatedObjectthis.state.animIn the render function, use the interpolation function.interpolateAccordingAnimatedThe current value of the object is calculated to obtain the corresponding rotation angle.rotateDegree. Let's assume that every time you click a button,AnimatedThe value of the object is 1, and the corresponding image turns 90 °. Therefore, SetinterpolateThe input range of the function is [0, 4], and the output range is ['0deg ', '360deg'] for linear interpolation. IfAnimatedThe current value of the object is 2, and the rotation angle is 180deg. In the component rendering structure, you need to useAnimated.divWrap the animation node and encapsulate the changed element attributes as css objects as stlye.Animated.div. In the click event, we first usestopAnimationStop the current animation and obtainAnimatedCurrent Value of the objectvalueAnd then useAnimated.springThe function enables a spring animation process to achieve a smooth animation effect. Since each rotation stops, we want the image flip angle to be an integer multiple of 90 °, so we needAnimated.springEnd value. Finally, we achieved the following results:

Pay attention to the following points during use:

  1. AnimatedThe value of an object and its interpolation result can only be appliedAnimated.divNode;
  2. interpolateBy default, linear interpolation is performed based on the input and output intervals. If the input value exceeds the input range, the interpolation result will be extended by default based on the output range. You can setextrapolateThe property limits the interpolation result range.

The animation does not directly modify the component.stateInstead of repeatedly triggering the render function, you can directly modify the attributes of elements through the components and methods of the newly created object. It is a very stable animation library in React Native. However, there is a low version browser compatibility problem in React, and there is a certain learning cost.

Conclusion

When we implement animation in React, we first need to consider the difficulty of the animation and use cases. For simple animation, we should first use css3 for implementation, followed by js-based time interval animation. If it is an element admission animation or an exit animation, we recommend that you combineCSSTransitionGroupOrTransitionGroup. When you want to achieve more complex animation effects, try some excellent third-party libraries to open the door to exciting animation effects.

Ps. All the sample code in this article can be viewed on github.

References:

React-transition-group

React-gsap-enhancer

A Comparison of Animation Technologies

React Animations in Depth

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.