DEV Community

Cover image for I'm SPRUNG! A react-spring series // Part 1: Intro & the useSpring hook 🦘
Kevin To
Kevin To

Posted on

I'm SPRUNG! A react-spring series // Part 1: Intro & the useSpring hook 🦘

I'm SPRUNG!

Yes this series is named after the 2005 song by T-Pain...

What is React Spring?

React Spring is a spring-physics based animation library. Instead of manipulating time, we give our elements mass, tension, and friction to mimic how things move from one position to another in real life.

Ok then... so how do we actually animate things?

First we have to get a few things out of the way.

1. The animated component

We can only animate animated components, these are provided by the react-spring library. We can also use a to denote an animated component as well

import { animated, a } from '@react-spring/web'

<animated.div /> // will animate

<span /> // won't animated

<a.h2 /> // will animate
Enter fullscreen mode Exit fullscreen mode

2. We define our springs in two ways:

  • As an config object
  • Or as an anonymous function passed into the hook
// This spring will run when the component mounts 

const spring = useSpring({
    from: {opacity: 0, 'translateY(100%)'},
    to: {opacity: 1, 'translateY(0)'}
})

// This spring will run based on state

const [active, setActive] = useState(false)

const spring = useSpring({
    opacity: active ? 1 : 0,
    transform: active ? 'translateY(0%)' : 'translateY(100%)'
})

/*
   And lastly we can use an imperative method. We use array 
   destructuring to receive a controller object. We just need 
   to pass an anonymous function with our config object.
   This method doesn't rely on the components lifecycle. 
*/ 

  const [styles, api] = useSpring(() => ({
    opacity: 0,
    transform: 'translateY(100%)'
  }));

  api.start(({
    opacity: 1,
    transform: 'translateY(0%)'
  }))

Enter fullscreen mode Exit fullscreen mode

Our first animation

Image description

const [active, setActive] = useState(false)

const spring = useSpring({
   opacity: active ? 1 : 0,
   transform: active ? 'translateY(0%)' : 'translateY(100%)' 
})

const handleClick = () => {
   setActive(state => !state)
}

return (
    <a.p style={spring}>Poof!<a.p>
    <button onClick={handleClick}>Click Me!</button>
)
Enter fullscreen mode Exit fullscreen mode

Above we see that the spring will only trigger based on the state of active. By default it will be invisible, and its starting position will be 100% of its origin on the Y axis (this means it will animate bottom - up). We've also passed the whole spring. But we can also use the spread operator...

return (
    <a.p {...spring}>Poof!<a.p>
    <button onClick={handleClick}>Click Me!</button>
)
Enter fullscreen mode Exit fullscreen mode

Our second animation

Image description

But what if we want to apply this spring to multiple elements in an array? React-spring has a dedicated hook for that useSprings, which we'll cover in the next post, but we can actually use the useSpring hook to do this, although it will be limited. All we have to do is map over the array and apply it to each rendered jsx element

/*
  Lets say we have four boxes we want to spin and turn into 
  circles
*/
const Example = () => {
   const [active, setActive] = useState(false)
   const elements = ['Item 1', 'Item 2', 'Item 3', 'Item 4']

   const animation2 = useSpring({
       transform: isActive ? 'rotate(720deg)' : 'rotate(0deg)',
       borderRadius: isActive ? '50% 50%' : '0% 0%',
       backgroundColor: isActive ? '#FF7518' : 'rgb(255, 255, 255)',
       color: isActive ? 'rgb(255, 255, 255)' : 'rgb(0, 0, 0)',
       transformOrigin: 'center',
   });

   const handleClick = () => {
      setActive(state => !state)
   }

   return (
      {elements.map(el => <a.p style={spring}>{el}<a.p>)}
      <button onClick={handleClick}>Click Me!</button>
   )
}
Enter fullscreen mode Exit fullscreen mode

This is nice if you simply want all the elements to have the same animation all happening at once.

Conclusion

Things to note about the useSpring hook:

  • Components will reverse their animation when tied to a state variable. If using the imperative method, springs will jump from the end state to the beginning position and run again

  • Remember that your components, even if their opacity is set to 0, they are still mounted on the DOM. They're never unmounted. We will take a look at mounting and un-mounting elements using the useTransition hook in the future

This wraps up the first part of the react-spring series! So stay tuned for part 2 on the useSprings hook!

Top comments (0)