React has been one of our favorite tools for creating interfaces for a while now. In order to make apps more playful and engaging, we’ve tested several animation libraries, including Anime.js, Popmotion, and the focal point of this blog post: react-spring. The latter turned out to be a fantastic tool for building lightweight animations that feel natural.
I’m Martin, a lead frontend developer at Apptension, and in this blog post, I’ll guide you through the basics of react-spring. Let’s start with a short overview of this library.
What is react-spring?
React-spring is a spring-physics based animation library. Its distinguishing features are:
- ability to cast data into motion easily,
- easy-to-use API with React hooks,
- imperative and declarative API combined,
- no limitations regarding the views structure.
It’s also multiplatform, which means it can be used for web as well as mobile React Native apps or to animate any values with universal export(lack of native elements and color interpolation).
Essentially, it’s a library that can fundamentally change your approach to animating elements. It will also allow you to achieve smooth, natural-looking animations. It’s possible thanks to spring-physics, the basis of this library.
You may also like: How to manage AWS ECS environment variables with Chamber?
Introduction to spring-physics
Instead of relying on time-based animations, react-spring uses physical properties:
- Velocity
- Mass (when mass is higher, the element needs more velocity to be moved and more time to stop)
- Friction (higher friction reduces velocity and bounciness)
- Tension (higher tension reduces the impact of friction).
In my experience, it’s easier to define motion precisely using physical attributes like these. On top of that, react-spring animations are highly responsive—when a value changes, the animation follows to the new point naturally, without any cuts.
Springs vs. time-based animations
Let me reiterate: spring-physics-based animations look really natural. For instance, when your animation stops before completion and changes direction, the movement will be caused by the opposite force and will continue naturally till it achieves the next value. With time-based animations, the movement would be stopped and restarted with new values.
Worth checking: How to combine React Query & Constate? Practical guide
Still, react-spring allows you to create time-based animations when you feel like it.
Spring vs time-based animation movement example
What can you animate with react-spring?
The list of elements that you can animate using react-springs includes:
- numbers,
- CSS transform values e.g. “translateY(100%)” to “translateY(0%)”,
- strings of 2 numbers e.g. “0% 100%” to “100% 0%”,
- Colors, e.g., “#ffffff” to “#000000”, “black” to “white”,
- arrays, e.g., [0, 0, 1] to [1, 1, 0] (any animatable value can be animated inside an array),
- non-animatable string values, e.g., “visibility: hidden” to “visibility: visible“,
- SVG attributes e.g. stroke-dasharray.
Common API
The Common API is a config that is the same between all the react-spring hooks. It allows us to define proper animation behavior and access the basic properties, e.g., from/to/reset/onRest.
In order to animate, you have to import a special factory—animated. It extends native elements to handle animated values. You can wrap an existing component or a DOM element. Animated can also be used with styled components or elements directly exported from animated, e.g., “animated.div”.
Basic properties
Config
To create a config, you can also use one of the generic presets imported from react-spring.
Value interpolation
Interpolation is supported out-of-the-box in react-spring. You have a couple of options for interpolating single values:
- passing range, output, extrapolate props in an object,
- passing two arrays (an input and an output),
- transforming an existing value into a different form (e.g., “5” to “translateY(5px)”).
You can also combine values from different spring definitions into one value using an “interpolate” helper available in the react-spring package.
Extrapolate property comparison
Might be interesting: What is a boilerplate? Meaning, history and examples
Hooks API
As of now, there are five hooks in react-spring. Let’s go through them one by one.
useSpring is a basic hook that allows you to animate values with a single spring definition passing properties and the config. You can also use it to define async/await scripts and chains when you need a couple of steps in the movement.
useSprings is a hook for creating multiple springs. For each of them, you can define a different config.
useTrail is another hook for creating multiple springs. This one is used when every element should follow the previous one, e.g., for stagger animations. Here, you can only define one spring config.
useTransition is a hook for creating a spring that defines the element transition. It supports trails with a strictly defined delay between elements. Here, you have an extra config allowing you to determine the animation in the from/enter/update and leave states.
With this hook, you can create atomic transitions as well as transitions on multiple elements. Similarly to useSpring, useTransitions enables you to define async/await scripts and chains.
useChain is a hook you can use for combining multiple react-spring hooks animations. For instance, you can combine a spring animation with a transition. It allows you to define a moment in time when the next chain element animation should be fired.
useChain with useTransition example
Performance
It’s important to remember that react-spring doesn’t rely on React to render updates frame-by-frame. As a result, animations are more performant.
Still, when you render a large number of elements, make sure to use the useMemo React hook. You might also want to use a “native” flag for render-props API to achieve better performance.
I hope that my blog post and the examples I’ve put here help you make sense of react-spring. If you’re anything like me, you’ll definitely appreciate the precision and easiness with which you can animate elements using this library.