Back

Integrating Velocity into React for Enhanced Animations

Integrating Velocity into React for Enhanced Animations

It is no news that web animations turn static web properties into dynamic and interactive elements crucial for enhancing user experience and sustaining engagement. They are visually appealing, help simplify complex UI interactions, and provide subtle cues that can improve a project’s responsiveness and quality. This article shows how to use Velocity.js with React for better animations.

This article emphasizes how to create enhanced web animations within a React application using Velocity.js, a powerful JavaScript library that was created by Julian Shapiro to easily create complex animations for HTML and SVG elements. We will highlight the integration methods and advanced animation techniques, and provide best practices for effective animation implementation.

What is Velocity.js?

This is a JavaScript library that is known for its fast performance and comprehensive capabilities for animating DOM elements. It is an animation toolkit to make web animations as fast and efficient as possible. Interestingly, it works with and without jQuery, offering high performance and a simple, easy-to-use API for creating complex animations. With this library, almost any CSS property can be animated, including properties not supported by CSS transitions.

What to know about React animation?

Implementing animation is an integral part of creating an application as it improves overall user experience, which is, in turn, one of the most critical parts of branding. React itself does not have a built-in system for this, so the animation can be achieved in two ways; one way is using the useState hook and CSS transitions, while the other is using external libraries like Velocity.js, which we covered in this article.

Why Velocity.js for React Animations?

There are numerous benefits of this animation method:

  • Lightweight and Easy to Learn: Its API is comparatively straightforward and has a reduced footprint compared to more complex animation libraries. Thus, it is well-suited for tasks requiring the incorporation of fundamental animations while lessening the learning curve.
  • User-Friendly Animation Control: It facilitates animations using a declarative approach. The library manages the intermediate stages while you specify the desired end state and animation properties. It streamlines animation code and makes it simpler to maintain.
  • Integration with React Existing State Management: It can seamlessly integrate with state management mechanisms, allowing you to trigger animations based on changes in your component state. This enables animations to react dynamically to user interactions and events.
  • Performance: It is highly optimized for performance, providing smooth animations even on complex web elements. Its efficient animation engine provides minimal jank and increases frame rates, which is vital for offering a responsive user experience in applications.
  • Direct DOM Manipulation: It directly manipulates DOM properties, bypassing the virtual DOM reconciliation process. This approach can be more efficient for animations than the React default rendering mechanism, especially for animations requiring frequent updates or interactions.
  • Feature-rich API: It offers rich features and options for creating animations, including support for CSS properties not covered by CSS transitions or animations.

This library is a solid choice for your React projects, where you must add basic or moderate complexity animations with a user-friendly approach. Its simplicity of use, performance optimizations for simpler animations, and interaction with React state management make it an adaptable solution for various animation requirements.

Integrating Velocity.js with React

Conventionally, there are two ways to incorporate the library into your project:

Using velocity-animate

Straightforward, to say the least, this method involves installing the library using npm or yarn. Here is how you can do it:

First, install Velocity.js and its dependencies:

npm install velocity-animate

Then, in the React component file, you import the library:

import Velocity from 'velocity-animate'; // The Import

Next, you animate the DOM node. Here is the basic syntax:

Velocity(element, properties, options);

The element is the DOM node to be animated, while properties is an object where you define the CSS properties and their target values for the animation. Finally, the options is an object where you can specify animation options such as duration and complete (the callback function to execute after the animation completes).

Here is an example to illustrate the implementation:

Velocity(
  this.adviceText,
  { opacity: 0 },
  {
    duration: 500,
    complete: () => {
      this.setState({ advice }, () => {
        Velocity(this.adviceText, { opacity: 1 }, { duration: 500 });
      });
    },
  },
);

OUTPUT Untitled video - Made with Clipchamp (1)

FULL CODE REPOSITORY HERE

The function Velocity() provided by the library animates DOM elements. The first argument, this.adviceText, is an element that refers to a DOM element we want to animate.

The second argument, { opacity: 0 }, specifies the CSS properties and their target values to animate. In this case, it sets the element opacity to 0, making it completely transparent.

The third argument, { duration: 500, complete: () => { ... } }, contains options for the animation. The duration: 500 specifies the duration of the animation in milliseconds. With this example, the opacity animation will take 500 milliseconds to complete.

The complete: () => { ... } is a callback function that is called when the animation completes. Inside this callback, another animation triggers after updating the state. Also, within the complete callback, this.setState({ advice }, () => { ... }) is called to update the state with new advice fetched from the API. The setState function in React allows you to update the component state.

In summary, this integration approach is straightforward to understand and apply. In the example, Velocity.js is utilized in the React app to animate the advice text opacity to 0, making it invisible. After fetching the new advice and updating the state, it animates the advice text opacity back to 1, making it visible again.

Using velocity-react

It is a React-centric approach to animating components by providing a declarative syntax within JSX for defining animations alongside our code.

npm install velocity-react

The code above provides a VelocityComponent that simplifies animation integration. Here is an example of the application:

import { VelocityComponent } from "velocity-react";

class App extends React.Component {
  state = { advice: "", isAnimating: false };

  componentDidMount() {
    this.fetchAdvice();
  }
  fetchAdvice = () => {
    this.setState({ isAnimating: true });
    axios
      .get("https://api.adviceslip.com/advice")
      .then((response) => {
        const { advice } = response.data.slip;
        this.setState({ advice });
      })
      .catch((error) => {
        console.log(error);
      })
      .finally(() => {
        this.setState({ isAnimating: false });
      });
  };

  render() {
    const { advice, isAnimating } = this.state;

    return (
      <div className="app">
        <div className="card">
          <VelocityComponent
            animation={{ opacity: isAnimating ? 0 : 1 }}
            duration={500}
          >
            <h1 className="heading">{advice}</h1>
          </VelocityComponent>
          <button className="button" onClick={this.fetchAdvice}>
            <span>Next Quote</span>
          </button>
        </div>
      </div>
    );
  }
}

export default App;

OUTPUT 1

Here, the VelocityComponent encapsulates the heading to animate its opacity. If the variable isAnimating is true, the opacity is set to 0, indicating a fade-out effect. Inversely, if isAnimating is false, the opacity is set to 1, indicating a fade-in effect.

It seamlessly integrates with the component lifecycle, enabling animations to occur on mount, update, or unmount, synchronized with the rendering process. Animation state management is simplified by controlling animation parameters using state variables and triggering animations based on changes in component state or user interactions.

Advanced Animation Techniques

Velocity.js has several techniques applicable to elements and properties that enhance a webpage animation. Here, we will discuss some techniques and how they can be used for an optimized web experience.

Chaining

It refers to the ability to queue up multiple animations on a single element and execute them sequentially by defining a series of animations to be performed on an element one after the other.

This technique allows you to define multiple animation properties and values. It also allows you to specify options for each animation, such as duration, easing, and callback functions, while executing these animations in a specific order, one after the other, on the same element.

Here is an example of Chaining:

Velocity(
  this.adviceText,
  { scale: 1.5 },
  { duration: 500, easing: "easeInOutQuart" },
).then(() => {
  Velocity(
    this.adviceText,
    { scale: 1 },
    { duration: 500, easing: "easeInOutQuart" },
  );
});

OUTPUT Untitled video - Made with Clipchamp (1) (1)

This code snippet performs a series of chained animations. It first fades out the text, then fades it back in, scales it up, and finally scales it down, all with specified durations and easing functions.

Scroll and Reversal

Scroll refers to the animation of an element’s scroll position. It is typically used for smoothly scrolling an element to a specific position within a container. It can help create custom scrolling effects or implement smooth scrolling behavior on a webpage.

Conversely, reversal refers to the ability to reverse an animation applied to an element. It means you can play an animation forward and reverse it to its original or previous state. This feature is handy for creating interactive animations or user-controlled effects where animations can be toggled back and forth.

Here is an example:

// Scroll the advice text up
Velocity(
  this.adviceText,
  { translateY: "-100%" },
  { duration: 1000, delay: 1000, easing: "easeInExpo" },
);

// Reverse the scrolling animation
Velocity(this.adviceText, "reverse", {
  duration: 1000,
  delay: 3000,
});

OUTPUT Untitledvideo-MadewithClipchamp3-ezgif.com-resize

The code effectively scrolls the this.adviceText element upwards initially and reverses the scrolling animation after a delay, bringing the text back to its original position.

Transform

This property allows the application of various transformations to an element, such as scaling, rotating, skewing, and translating.

Here is an example of Transform:

Velocity(
  adviceTextRef.current,
  { translateX: "100px", rotateZ: "45deg", opacity: 0 },
  {
    duration: 500,
    complete: () => {
      setAdvice(advice);
      Velocity(
        adviceTextRef.current,
        { translateX: "0px", rotateZ: "0deg", opacity: 1 },
        { duration: 500 },
      );
    },
  },
);

Untitled video - Made with Clipchamp (1) (1)

In the example, the element is translated 100 pixels to the right, rotated 45 degrees clockwise, and its opacity set to 0. This sequentially creates a movement, rotation, and fade-out effect lasting 500 milliseconds. Upon completion, a callback function triggers, updating some advice state variables with the value of advice.

Subsequently, another animation is initiated to reset the element properties to their original state: translate back to its original position, rotation reset to 0 degrees, and opacity set to 1, resulting in a movement back, rotation reset, and fade-in effect, also lasting for 500 milliseconds.

Hook

These are individual components of multi-value CSS properties. For instance, CSS’s textShadow property comprises multiple values like horizontal offset, vertical offset, blur radius, and color. With this property, separately animating each component, such as textShadowX, textShadowY, and textShadowBlur, is possible. Similarly, other multi-value properties like boxShadow and clip can be animated this way, too.

Here is an example:

Velocity(
  adviceTextRef.current,
  {
    textShadowBlur: "10px",
    opacity: 0,
  },
  {
    duration: 500,
    complete: () => {
      setAdvice(advice);
      Velocity(
        adviceTextRef.current,
        {
          textShadowBlur: "0px",
          opacity: 1,
        },
        {
          duration: 500,
        },
      );
    },
  },
);

The code above establishes a completion callback function to run once the initial animation concludes. It then triggers the setAdvice(advice) function to refresh advice content. The same element is animated again to revert its text-shadow blur to “0px” and its opacity to 1, effectively unveiling the element again. This subsequent animation also lasts 500 milliseconds.

Mock

During UI testing, you can enable $.Velocity.mock = true;, essentially instructing all Velocity animations to execute instantly with zero milliseconds duration and delay. This indicates that the values are implemented immediately in the following animation cycle. The feature proves exceptionally useful during repetitive UI testing, prioritizing the validation of end values over the intricate animation transitions.

Here is the basic syntax:

Velocity.mock = 10;

Untitled video - Made with Clipchamp (4) (1)

It affects all the animation within the code and will make it run 10 times faster than its average speed.

Value function

You can provide functions as property values, executed once per element, just before the animation starts. As a result, during looping or reversing, these functions aren’t continuously invoked.

The syntax is as follows:

$element.velocity({
    opacity: function() { return Math.random() }
});

Force-feeding

In the conventional animation approach, DOM is inspected to establish the starting value for each property undergoing animation. However, Velocity.js introduces a different method called force-feeding, wherein users directly specify the initial values, bypassing the need for DOM querying entirely and effectively eradicating layout thrashing. It is an indispensable technique in high-pressure scenarios involving extensive DOM querying that could seriously affect the framerate. Yet, for most low-pressure UI animations, it is an excessive optimization.

Here is an example:

$element.velocity({
  /* Two-item array format. */
  translateX: [500, 0],
  /* Three-item array format with a per-property easing. */
  opacity: [0, "easeInSine", 1],
});

Here, we initialize the translateX property with a start value of 0 because we recognize that the element has not been translated yet. Similarly, we set the initial opacity value to 1, assuming it has not been modified from its default state. We explicitly define the starting values for both properties based on what we know and intend them to be for the initial animation state.

Key Considerations and Hacks on Velocity.js

Key considerations to keep in mind include:

  • Performance: Although it provides powerful functionalities, utilization should be optimized to prevent potential performance complications. Prioritize mobile device optimizations and investigate code-splitting to reduce bundle sizes.
  • State management: To manage animation states or implement a specialized state management solution such as Redux, it is necessary to utilize state plugins, namely useState and useEffect.
  • Concurrent Animations: Expected results may ensue when multiple animations are executed concurrently. To address this issue, consider implementing a queue system or React-centric animation libraries that gracefully manage conflicts.

Here are the hacks I would like to point out:

  • Maximizing the utility of ReactState and useEffect hooks to govern animation states and initiate animations based on component state alterations would be the best.
  • Ensure seamless integration by utilizing conditional rendering techniques to display animation components by the state of your application.
  • Craft custom hooks to encapsulate reusable animation logic and configurations, fostering cleaner and more maintainable code.
  • Employ optimization techniques such as throttling, debouncing, and passive loading animations to bolster overall performance.
  • Explore alternative libraries like React Spring or Framer Motion, built atop Velocity.js, which offer a more React-centric approach to animation, potentially streamlining development efforts.

Conclusion

Integrating Velocity.js into a React application, whether through direct implementation or via the velocity-react library, offers a powerful means to enrich user interfaces with smooth and captivating animations. By leveraging the robust features of the two libraries, developers can seamlessly incorporate animations into their applications, enhancing usability and engagement while ensuring that animations not only delight users but also contribute to a fluid and responsive user experience across different devices and platforms. Happy Coding.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay