Spring it on! The complete guide to React Spring. 🧵
Tags: react, webdev, tutorial, javascript
Published: 2020-10-02 14:27:23

Hey, are you the one who's keen on discovering new possibilities with [Hooke's Law](https://phys.org/news/2015-02-law.html)? Remember the following image which tells us how elasticity works?

![Hooke's Law illustration](https://scx2.b-cdn.net/gfx/news/hires/2015/54e1ebda060dc.jpg)
<figcaption>Science nerds, just don't go too deep into this...</figcaption>

Well, I'm no a Physics professor to introduce you to the world of how springs and hooks work but I can certainly show you how you can achieve the same level of _flexiblity_ on a React-based application through a very popular library called **[React Spring](https://www.react-spring.io)**. 😍

![Spring GIF](https://media.giphy.com/media/wNipYAoZ3iaEE/giphy.gif)
<figcaption>Spring is here! 🙃</figcaption>

---

## What is React Spring? 🤔

> React Spring is a **spring-physics based animation library** which gives all the necessary tools to make simple yet powerful animations and interactions via the different interpolations and transitions provided to us.

So yes, you get all the easings and smoothness you would like for your components or elements.


### Understanding the _spring_ 🧐

Before we start coding let's take a moment to appreciate Physics (I loved that subject 🥺). The term 'spring' is heavily involved with this library.

Just like we have the following different forces applied to a spring attached to a certain point 'A':

- Force of gravity.
- Acceleration of gravity.
- The spring force.

![Spring forces GIF](https://i.imgur.com/7CCH51r.gif)

[And more](https://www.physicsclassroom.com/class/waves/Lesson-0/Motion-of-a-Mass-on-a-Spring), in the same fashion we describe a _spring_ in React Spring library as something which:

_does NOT have a defined curve or a set duration._

Hence all the animations are done in terms of time and curves. This is where React Spring comes into play. Typically, we would have normal [`@keyframes`](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes) animations in CSS which basically deals with time-based animation. Here, due to the nature-inspired easings, the animations feel more natural.


## What we'll be making? 😏

First, we'll make this basic transition to understand how things work:

![Text transform demo](https://dev-to-uploads.s3.amazonaws.com/i/ym1ngwg7i46i0e5ldyvp.gif)
<figcaption>We'll be using React Hooks in this!</figcaption>

### Let's spring it on! 😎

**Step 1: Installation**

After you've [created a new React project](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app), open up your terminal window and run the following command:

```
npm install react-spring
```
This should install all the necessary files related to the library.


**Step 2: The Toggle Component**

Create a new file under the _src/_ folder of your project called _Toggle.jsx_.

Start with the usual stuff like exporting the component and returning a container `div` which has two children; first, the `<h1>` heading called "Hello" and next a `<button>` "Toggle".

Nothing fancy here. So, just add the 'fancy'. We'll be using the `useState` Hook in order to handle the state of our toggle. Start by importing it and giving it the `isToggled` state variable. The initial value of the state should be set to `false` as we don't want the toggle state to show at first.

```js
const [isToggled, setIsToggled] = useState(false);
```

Next, to start using React Spring, we need to import the `useSpring` hook. This turns a normal value of an element into an animated-value.

Let's name our animation as _fade_ and inside the `useSpring` hook object we'll define all the animations we need. As you can see in the demo above, when the toggle button is clicked, the text changes:

- Its color from black to green.
- Its font size from small to big.
- Its position.

As you can see in the documentation, the `useSpring` hook takes in various properties just like a normal CSS code would take. But here we have a React Hook also, hence we pass the `color`, `transform`, and `fontSize` properties (notice the change in syntax when compared to CSS!) with the `isToggled` variable.

So, if the toggle has not changed its state, then the `color` would be `#000` else when it does change (when the button is pressed), we set it to `green`.

The same goes for the other two properties we want to animate:

```jsx
const fade = useSpring({
    color: isToggled ? '#000' : 'green',
    transform: isToggled
      ? 'translate3d(0, 15px, 0)'
      : 'translate3d(0, 15px, 0)',
    fontSize: isToggled ? '2rem' : '3rem',
  });
```

Okay, but now we haven't written the `<button>` functionality! Let's write it. We add an `onClick` event which passes in the `setIsToggled` Hook function whose job is to simply change the boolean value of `isToggled` variable. 

```jsx
<button onClick={() => setIsToggled(!isToggled)}>Toggle</button>
```

For the final part, we use the `animated` prop provided by the library (make sure to import it). We add this prop in whichever element we want to animate. Here, on clicking the "Toggle" button we want to animate the heading so, we change the tag from `<h1>` to `<animated.h1>`. 

**Step 3: Add the Toggle Component**

At last, simply go back to the _App.js_ file and return the newly created component. You can also add some styling if you like.

```jsx
function App() {
    return <Toggle />
}
```

As soon as you do this, you can play with the newly created spring animation! Notice that you didn’t have to care about the easing :)

### Take a step further 🚀

How about we move ahead and make this?

![React Spring demo](https://dev-to-uploads.s3.amazonaws.com/i/apv1qcr5ggkmtn6eny5a.gif)

Looks exciting right? It's somewhat complex though, Here's what we need to do:

We'll write the code inside _App.js_ itself. Begin by importing the library.

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

Inside the `return()` method, we have a single `<animated.div />` which takes in two [React's mouse synthetic events](https://reactjs.org/docs/events.html#mouse-events): `onMouseMove` and `onMouseLeave` for the actions we need to perform. These take in the `x` and `y` coordinates inside the current viewport/container.

```jsx
return (
    <animated.div
      onMouseMove={({ clientX: x, clientY: y }) => set({ xys: calcXY(x, y) })}
      onMouseLeave={() => set({ xys: [0, 0, 1] })}
      style={{ transform: props.xys.interpolate(perspective) }}
    />
  );
```

Here, we pass in the `clientX` and `clientY` to be calculated by the `calcXY()` function. 

The `calcXY` is a simple function which takes `x` and `y` as its arguments and uses DOM's [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) interface to get respective `width` and `height`.

```jsx
const calcXY = (x, y) => [
  -(y - window.innerHeight / 2) / 15,
  (x - window.innerWidth / 2) / 15,
  1.0,
];
```

To set the value of `xys` as desired, we make a new global constant and use the `perspective()`, `rotateX()`, `rotateY()` and `scale()` properties.

```jsx
const perspective = (x, y, s) =>
  `perspective(500px) 
   rotateX(${x}deg) 
   rotateY(${y}deg) 
   scale(${s})`;
```

Notice the use of [JavaScript's template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to dynamically change the corresponding values. But by just declaring the new `perspective` constant, it won't work. We need to use it inside the `style` attribute of the `<animated.div />` tag as follows:

```jsx
style={{ transform: props.xys.interpolate(perspective) }}
```

We pass the `perspective` inside the `interpolate()` function. As per the [docs](https://www.react-spring.io/docs/props/performance):

> The interpolate function either takes a function or a an object which forms a range. 
Interpolations can also form chains which allows you to route one calculation into another or reuse them.

Now it's time for some physics stuff (again!). Inside the `useSpring()` we first pass in the default `xys` value (which simply translates to the X, Y, and the Z coordinates in three dimensions) and then using the `config` property, we can manually define how much `mass`, `tension` and `friction` an element can have! 

Exciting right? All of this is possible thanks to React Spring's [Common API](https://www.react-spring.io/docs/hooks/api). You can view all the examples and an interactive demo on their website.

As for the styling, it can be achieved quite easily with CSS:

```css
.card {
  width: 30rem;
  height: 30rem;
  border-radius: 15px;
  background-image: url(https://images.pexels.com/photos/4870974/pexels-photo-4870974.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260);
  background-size: cover;
  background-position: center center;
  box-shadow: 0px 10px 30px -5px rgba(0, 0, 0, 0.3);
  transition: box-shadow 0.5s;
}

.card:hover {
  box-shadow: 0px 30px 100px -10px rgba(0, 0, 0, 0.4);
}
```

Here's our entire spring code:

```jsx
const calcXY = (x, y) => [
  -(y - window.innerHeight / 2) / 15,
  (x - window.innerWidth / 2) / 15,
  1.0,
];

const perspective = (x, y, s) =>
  `perspective(500px) rotateX(${x}deg) rotateY(${y}deg) scale(${s})`;

function App() {
  const [props, set] = useSpring(() => ({
    xys: [0, 0, 0.5],
    config: { mass: 5, tension: 200, friction: 100 },
  }));
  return (
    <animated.div
      className='card'
      onMouseMove={({ clientX: x, clientY: y }) => set({ xys: calcXY(x, y) })}
      onMouseLeave={() => set({ xys: [0, 0, 1] })}
      style={{ transform: props.xys.interpolate(perspective) }}
    />
  );
}
```

I hope this cleared your basic understanding of how you can animate your components in React Spring, there are tonnes of other possibilities with this library. Check out all the examples [here](https://www.react-spring.io/docs/hooks/examples).

---

_Thanks for reading, I appreciate it! Have a good day. (✿◕‿◕✿)_

---
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr">Your IDE may be in dark mode but are your Windows OS and related apps late-night friendly too? 👀 Learn more here: <a href="https://t.co/ww6fY8HUju">https://t.co/ww6fY8HUju</a><br><br>Image source: <a href="https://t.co/cB3ntpgxIq">https://t.co/cB3ntpgxIq</a><a href="https://twitter.com/hashtag/DevHumour?src=hash&amp;ref_src=twsrc%5Etfw">#DevHumour</a> <a href="https://twitter.com/hashtag/DarkMode?src=hash&amp;ref_src=twsrc%5Etfw">#DarkMode</a> <a href="https://twitter.com/hashtag/Developer?src=hash&amp;ref_src=twsrc%5Etfw">#Developer</a> <a href="https://t.co/Xz4Y4FAlI6">pic.twitter.com/Xz4Y4FAlI6</a></p>&mdash; Microsoft Developer UK (@msdevUK) <a href="https://twitter.com/msdevUK/status/1310485401677828097?ref_src=twsrc%5Etfw">September 28, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
---

#### [📫 Subscribe to my weekly developer newsletter 📫](https://mailchi.mp/f59beeac6b9b/devupdates)

##### PS: From this year, I've decided to write here on DEV Community. Previously, I wrote on Medium. If anyone wants to take a look at my articles, [here](https://medium.com/@vaibhavkhulbe)'s my Medium profile.