Sunday, April 18, 2021

Animations with Spring in ReactJS

Today I was looking to add some animations to my project, and tripped over this Spring package for React. I found that it did the job far better than trying to use the traditional CSS animations in React.

To use Spring, you first need to install it with:
npm i react-spring

Then on your component you'll need to import it
import useSpring, animated from 'react-spring';

Then we create an object with the styles that we want. The Spring library will then animate our elements with this object whenever the page is re-rendered. In this case the variables topDist and leftDist are taken from a useState, and whenever they're changed, it will animate.
const springProps = useSpring(
    top: topDist + "px",
    left: leftDist + "px"
);

Finally, on the HTML (return function) we use the animated function, and set its style to what we've declared.
<animated.div className="pawn" style=springProps />

Here's a working example:

import React, { useState } from 'react'
import { useSpring, animated } from 'react-spring';
import './App.css'
function App() {
    const [topDist, setTopDist] = useState(0);
    const [leftDist, setLeftDist] = useState(0);
     const  springProps = useSpring(         top: topDist+"px",         left: leftDist+"px",
    );
return (
        <div className="App">
            Top: <input type="text" value={topDist} onChange={e=>setTopDist(e.target.value)}/>
            Left: <input type="text" value={leftDist} onChange={=> {setLeftDist(e.target.value)}}/>
            <animated.div className="pawn" style={springProps} />
        </div>
    );
}

export default App;
CSS:
.container {
  positionrelative;
  border1px solid black;
  height200px;
  width200px;
}

.pawn {
  positionabsolute;
  height30px;
  width30px;
  border-radius15px;
  background-colorbrown;
}

In the case we want to use it on multiple elements, we could use multiple useSpring's, or we can use the useSprings.

First, we'll need to import the import from useSpring to useSprings. Then we'll need an array with multiple entries, like:

const circles = [1,2];

Then we'll useSprings instead of useSpring. In this case, for simplicity,
we'll just make the 2nd circle circle to move twice as much as the 1st one.

const springs = useSprings(circles.length, circles.map( b => {
    return {
        top: topDist*b+"px",
        left: leftDist*b+"px",
    }
}));

And finally we update the render function:

<div className="container">
    {springs.map(props => (<animated.div className="pawn" style={props} />))}
</div>