Getting Animated! With React-Spring #2: The useSpring Hook
Tags: react, javascript, design
Published: 2020-08-25 02:28:01

Welcome to part two of our series on animating react with `React-Spring`! In the  [first article](https://www.sabinthedev.com/getting-animated-with-react-spring-1-what-is-react-spring/) we took a quick look at what `React-Spring` is, what makes it awesome, and took a peek at what the api has to offer. Today we're going to take a bit deeper of a dive into the first hook the api offers, `useSpring`.

---

## Table of Contents
- [What We're Building](#what "What")
- [`useSpring`](#usespring "usespring")
- [Putting `useSpring` To Use](#use "Putting to use")
- [Triggering Animations On Interactions](#trigger "Triggering")
- [Conclusion](#conclusion "Conclusion")

*The code for this section can be found on [github](https://github.com/sabinadams/getting-animated-1)*

---
<a name="what"></a>
## What We're Building

The goal of this section will be to use the `useSpring` hook to take a profile card:

![Profile](https://res.cloudinary.com/sabinthedev/image/upload/v1597991975/getting-animated-2/completed-profile-card.png)

and build out some loading and hover animations to give it a little more personality 😁

![Animated](https://res.cloudinary.com/sabinthedev/image/upload/v1597992038/getting-animated-2/animated-profile-card.gif)

---

<a name="usespring"></a>
## useSpring

### Basic Use

The first hook we'll look at is called `useSpring`. In essence, this hook simply animates a data value from point a to point b. In its most basic form, a spring will look something like this:

```jsx
// Make sure to import the hook and the animated privitive
import { useSpring, animated } from 'react-spring'

const props = useSpring({ to: { opacity: 1 } })
// ... or the shorthand version of the above
const props = useSpring({ opacity: 1 })
```

Here's what this is doing:

We are passing in to the hook an object defining what values we want animated and what the key names of those values are. In our case, we are saying we want to animate a value named `opacity` to a value of 1. Let's apply this animation to a `div` element:

```jsx
import React from 'react'
import { useSpring, animated } from 'react-spring'

function AnimatedDiv() {
    const props = useSpring({opacity: 1})

    return (
        <animated.div style={props}>  
            <p>I'm some text</p>
        </animated.div>
    )
}

export default AnimatedDiv
```
![Screen](https://res.cloudinary.com/sabinthedev/image/upload/v1597992099/getting-animated-2/im-some-text-animation.png)

You may notice that nothing really seems to be getting animated here. It has an `opacity` of `1` like we asked, but why wouldn't it? That's the default in a browser unless specifically styled otherwise. In order to see the animation in action let's add a `from` definition where we can define the initial setting of values we are animating.

```jsx
const props = useSpring({opacity: 1, from: { opacity: 0 } })
```

Now you should see your text fade in.

![fadein.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992149/getting-animated-2/Z9vWcShMk_q0wdzk.gif)

The important thing to remember here is that these *DO NOT* have to be styles. They key names are arbitrary and can be anything except for a few reserved keywords in the `react-spring` api.

For example, if we wanted to animate a value from 2 to 10 to display inside of a `<p>` tag, we could write the following:

```jsx
import React from 'react'
import { useSpring, animated } from 'react-spring'

function AnimatedParagraph() {
    const props = useSpring({ number: 10, from: { number: 2 } })
    return <animated.p>{ props.number }</animated.p>
}

export default AnimatedParagraph
```

![numCounterUnRounded.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992176/getting-animated-2/W9NmeZMTK_mifmwv.gif)

The examples above are very basic and use the default settings of the `useSpring` hook. Let's make a couple of changes to enhance the experience a bit:

- The animation is super fast, let's slow it down
- The values are long-trailing decimals... we'll use `interpolation` to round those up

### Configuration

`useSpring` has a bunch of  [configuration options ](https://www.react-spring.io/docs/hooks/api) that allow you to either change the duration of the animation, or adjust the physics of the spring-like calculation of values. Note that this is an *either-or* option. If you use the `duration` configuration option, you forfeit the physics aspect of calculating the values. In some cases this is fine and won't make much of a difference.

Let's use the `duration` configuration option to define how long we want our animation to take. To do this we'll add the `config` key.

```jsx
import React from 'react'
import { useSpring, animated } from 'react-spring'

function AnimatedParagraph() {
    const props = useSpring({ 
        number: 10, 
        from: { number: 2 }, 
        config: { duration: 2000 }
    })
    return <animated.p>{ props.number }</animated.p>
}

export default AnimatedParagraph

```

![2secondsNoRounding.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992216/getting-animated-2/h8z_pjiJG_jwptu0.gif)

Here, we've configured our animation to take 2 seconds (2000 milliseconds). Any other configuration options available in the common API also go in this `config` object. Now let's use `interpolation` to round the value and get rid of those pesky decimals. 

### Interpolation

Every animated value has attached to it a function named `interpolate`, which allows you to format or perform actions on the value before using it in the view. This function can either take in an object defining the interpolation, or a function with the value as its parameter. We'll use the function in our scenario to round the number.

```jsx
import React from 'react'
import { useSpring, animated } from 'react-spring'

function AnimatedParagraph() {
    const props = useSpring({ number: 10, from: { number: 2 }, config: { duration: 2000 }})
    return <animated.p>{ props.number.interpolate( num => Math.round(num) ) }</animated.p>
}

export default AnimatedParagraph
```

![2secondsRounded.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992288/getting-animated-2/FgiNLRpqR_ptmmhw.gif)

Great! Our simple animation is looking good 👍  These are just a few of the many options from `react-spring`'s  [common-api](https://www.react-spring.io/docs/hooks/api) that all of its hooks are build upon. Over the course of this series we will take a look at most of these options. 

--- 

<a name="use"></a>
## Putting `useSpring` To Use

Now that we know a little bit about the `useSpring` hook, let's create an animated profile card! 

![profileCard.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992338/getting-animated-2/UlnjUW1n__ahrsuo.gif)

This animation will be our first goal. Upon rendering the component, we want to scale the card up to full size. Note how the animation over-shoots the size a bit and bounces back to it's full scale. This is because of the spring-like nature of `react-spring`. In this animation we will make use of the `tension`, `mass`, and `velocity` configuration options to define how we want our spring to behave. 

First off, let's see what our un-animated component looks like. I won't be digging into the specific styling of components in this series so much, as our focus will just be the animations.

```jsx
import React from 'react'
import './ProfileCard.scss'

function ProfileCard() {

    return (
        <div className="cardWrapper">  
            <div className="profileCard">
                <div className="iconHolder">
                    <a className="fa fa-twitter"></a>
                    <a className="fa fa-facebook"></a>
                </div>
                <img src="https://www.w3schools.com/w3images/avatar2.png"/>
                <div className="divider"></div>
                <div className="details">
                    <h3 className="name">Sabin Adams</h3>
                    <p className="description">UI/UX Enthusiast</p>
                </div>
            </div>
        </div>
    )
}

export default ProfileCard
```

![Screen](https://res.cloudinary.com/sabinthedev/image/upload/v1597992370/getting-animated-2/Kt5wQUP7y_lbdtwp.png)

So where do we start? Honestly, to achieve our goal is quite simple. Here's what we need to think about in this scenario:

1. We need to use the `animated` primitive so we can use animated values in our view
2. We will be animating the scale from some smaller size to its full-size. To do this we will use the `transform` css property
3. There is also a `box-shadow` that gets adjusted, so our spring will need to adjust that as well *(Yes, springs can handle multiple values!)*

### Applying `animated`

So let's take this step by step. First thing's first, we want to support animated values! In our return, we'll apply `animated` to the div containing the profile card.

```jsx
return (
    <animated.div className="cardWrapper">  
        // ... Profile card markup
    </animated.div>
)
``` 

With that in place, we're ready to set up a spring and scale the card!

### Using `useSpring` to scale the card

As we say above, setting up a spring with a `from` and `to` value is easy. Springs handle tons of different value types. Some of these include any value available to the `transform` css property. We will be using the  `scale` property. You can read more about that [here](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale) if you'd like.

```jsx
const props = useSpring({
    transform: `scale(1)`,
    from: { transform: `scale(0.5)`}
})
```

As you've probably already figured out, this will start our profile card off at half its normal scale and animate it up to full-size. Now all we need to do is apply the animated values to the style of the animated div:

```jsx
import React from 'react'
import './ProfileCard.scss'
import { useSpring, animated } from 'react-spring'

function ProfileCard() {

    const props = useSpring({
        transform: `scale(1)`,
        from: { transform: `scale(0.5)`},
    })

    return (
        <animated.div className="cardWrapper" style={props}>  
            // ... Profile card markup
        </animated.div>
    )
}

export default ProfileCard
``` 

Let's see the result:

![profileCardAnimated.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992412/getting-animated-2/2_9nrgSnH_xa034x.gif)

Pretty cool, right? **BUT** it could be better! This animation works great but looks pretty static. I like my animations a bit bouncier and natural. Fortunately, the springy nature of `react-spring` allows us to accomplish that using configurations. Here are the configurations we will use:

```jsx
const props = useSpring({
    transform: `scale(1)`,
    from: { transform: `scale(0.5)`},
    config: {
        tension: 400,    // How much tension is on the spring
        mass: 2,         // The mass of the spring
        velocity: 5      // The initial speed of the movement
    }    
})
```

With these configurations, we will have a fairly tense spring. *Think of a spring that is being stretched and is ready to bounce back*. We've also added mass to it so that the weight of the spring will slow down the movement a bit and pull against the spring once it reaches the full-size. This will result in it overshooting a little, but slowly bouncing back to the final value. *Imagine when you drop one side of a spring and it bounces up and down until it comes to a smooth stop.* Finally, our velocity we added just makes the animation a bit more snappy initially. It doesn't have to build so much energy initially, it starts off with some quick movement. Here's the result:

![profileCardAnimatedBounce.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992457/getting-animated-2/SwcjwQgFf_mjxasz.gif)

Awesome! That looks way more natural and customized. Our final piece here to give the card a more realistic look is to add that shadow.

### Adding a `box-shadow` adjustment to the spring

Adding the shadow is super easy now that we already have our spring defined. We simply need to add the to and from values of the shadow and `react-spring` can handle deciding how to update the shadow. 

```jsx
const props = useSpring({
    transform: `scale(1)`,
    boxShadow: `0px 5px 15px 0px rgba(0, 0, 0, 0.30)`,
    from: { 
        transform: `scale(0.5)`,
        boxShadow: `0px 0px 0px 0px rgba(0, 0, 0, 0.30)`
    },
    config: { 
        tension: 400, 
        mass: 2, 
        velocity: 5 
    }
})
```

![profileCardAnimatedBounceShadow.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992503/getting-animated-2/l-2jdx1GN_rasnoy.gif)

---

<a name="trigger"></a>
## Triggering Animations On Interactions

The profile card is looking awesome so far! Currently, upon rendering the card is animated to bounce into view, but that's about it. Let's spice it up a bit more. When hovering over the card, I'd like it to *lift off* of the page a bit. To create this effect, we'll do the following when hovering: 

- Scale the card up a bit
- Adjust the shadow so it looks like the card is higher off the page

In order to achieve this on-hover effect, we will need to use the `useSpring` hook in a different way which provides us access to some helper functions `react-spring` provides. Here's what that will look like:

```jsx
const [ props, set, stop ] = useSpring(() => ({
    transform: `scale(1)`,
    boxShadow: `0px 5px 15px 0px rgba(0, 0, 0, 0.30)`,
    from: { 
        transform: `scale(0.5)`, 
        boxShadow: `0px 5px 15px 0px rgba(0, 0, 0, 0.30)`
    },
    config: {
        tension: 400, 
        mass: 2, 
        velocity: 5 
     }
}))
```

`useSpring` allows us to pass in a function that returns the configuration we desire for the spring rather than an object. This is super useful for many reasons, but the reason it is useful to us here is that it returns an array of items for us to use.

- props - The same props object the hook returns when using an object instead of a function 
- set() - This allows us to update the spring without causing a re-render of our component
- stop() - Stops the animation

In our hover animation, we will need to use the `props` object and `set()` function. 

### Animating onMouseEnter and onMouseLeave

To accomplish this, we will need to use our `set()` function when the mouse hovers over the element and when the mouse leaves the element. The `set()` function acts just like `useSpring` in that you pass it an object or a function that returns an object. This object contains the spring configuration you would like to update to. For example, consider the following code:

```jsx
const [props, set] = useSpring(() => ({
    height: 10,
    from: { height: 0 },
    config: { duration: 1000 }
}))

set({height: 20})
```

This will set up a spring that animates a `height` value from 0 to 10. Then afterwards, the animation is updated, however, to a height of 20. It will, because of this, animate the height to 20. What we are wanting is to trigger this update on an interaction rather than before the component is loaded. To do so, we will leverage the `onMouseEnter` and `onMouseLeave` props.

```jsx
// Set up our spring
const [props, set] = useSpring(() => ({
    transform: `scale(1)`,
    boxShadow: `0px 5px 15px 0px rgba(0, 0, 0, 0.30)`,
    from: { 
        transform: `scale(0.5)`,
        boxShadow: `0px 0px 0px 0px rgba(0, 0, 0, 0.30)`
    },
    config: { tension: 400, mass: 2, velocity: 5 }
}))

// Updated value generator
const updateHover = hovering => ({
    transform: `scale(${ hovering ? 1.1 : 1})`,
    boxShadow: `0px ${hovering ? '10px 20px' : '5px 15px'} 0px rgba(0, 0, 0, 0.30)`
})

return (
    <animated.div className="cardWrapper" style={props}
        onMouseEnter={() => set(updateHover(true))}
        onMouseLeave={() => set(updateHover(false))}
    >  
        // ... Profile card markup
    </animated.div>
)
```

Whoa! What's going on here? It's actually a lot simpler than it may seem. When the `onMouseEnter` and `onMouseLeave` events are fired, we are running the `set()` function. It's value is a function we defined above that, based on whether or not we are hovering, returns an object containing the newly configured values we would like to animate to. Here's the result:

![profileCardFinishedHover.gif](https://res.cloudinary.com/sabinthedev/image/upload/v1597992560/getting-animated-2/tx3YQ-Nw0_ghkzyb.gif)

Pretty awesome, right? And the cool part about that `set()` function is the fact that it does not require a re-render of the component. Because of that level of efficiency, `set()` is the preferred way to do animations that happen quickly and often. 

Here's a look at the entire component!

```jsx
import React from 'react'
import './ProfileCard.scss'
import { useSpring, animated } from 'react-spring'

function ProfileCard() {
    const [props, set] = useSpring(() => ({
        transform: `scale(1)`,
        boxShadow: `0px 5px 15px 0px rgba(0, 0, 0, 0.30)`,
        from: { 
            transform: `scale(0.5)`,
            boxShadow: `0px 0px 0px 0px rgba(0, 0, 0, 0.30)`
        },
        config: { tension: 400, mass: 2, velocity: 5 }
    }))

    const updateHover = hovering => ({
        transform: `scale(${ hovering ? 1.1 : 1})`,
        boxShadow: `0px ${hovering ? '10px 20px' : '5px 15px'} 0px rgba(0, 0, 0, 0.30)`
    })

    return (
        <animated.div className="cardWrapper" style={props}
            onMouseEnter={() => set(updateHover(true))}
            onMouseLeave={() => set(updateHover(false))}
        >  
            <div className="profileCard">
                <div className="iconHolder">
                    <a className="fa fa-twitter"></a>
                    <a className="fa fa-facebook"></a>
                </div>
                <img src="https://www.w3schools.com/w3images/avatar2.png"/>
                <div className="divider"></div>
                <div className="details">
                    <h3 className="name">Sabin Adams</h3>
                    <p className="description">UI/UX Enthusiast</p>
                </div>
            </div>
        </animated.div>
    )
}

export default ProfileCard
```

---

<a name="conclusion"></a>
## Conclusion

`useSpring` is an awesome tool with so many different configurations and options. As you saw above, creating animations both simple and complex is fairly simple, and the extent of what the hook can do goes beyond what was covered here. I recommend reading the [docs](https://www.react-spring.io/docs/hooks/use-spring) on this hook to see what else it offers. Some specific features being its ability to script and chain different animations together in one spring. 

I hope you enjoyed jumping in and animating our profile card! In our next session, we will look at the `useSprings` hook and use that to generate a list of profile cards with individual configurations. 

Thanks for the read, and happy animating!