Basics of React Spring: Learn to animate the correct way ;)

Basics of React Spring: Learn to animate the correct way ;)

Animations are so powerful tool if you want to build a personal page or any web-page in general.

Why?

Because they make your website more lively and animators tend to put a lot of their personalities in that and, of course, visitors will enjoy more be on a lively website than a boring page, right?

For that, I think every frontend developer must learn to animate. So, I've been searching for what is the best library out there that can make me start to animate. It needs to be a react kind of library cause I use React, performant and can make any powerful animation. React Spring was a perfect choice because it inherits animated's powerful interpolations and performance, as well as react-motion's ease of use.

In this article, I will explore with you all the basics you need to start animating with React Spring. After you read this, you should be comfortable using this library and create amazing animations easily.

Fundamentals of the React Spring Library:

In React Spring there are 5 hooks:

-useSpring: Create a single spring that lets you move data from a to b.

-useSprings: Multiple springs with different datasets. So you can run a list of animations "springs".

-useTrail: Multiple springs with the same dataset. One will run after the other.

-useTransition: Basically used when you need to remove, update, or add a component.

-useChain: Used when you need to chain multiple animations together.

What we will build

We will build one exiting and simple animation for every hook. I want that you get the hang of it before starting the advanced type of animations. We will move slowly, however effectively, because animations are different than just writing CSS or JS and you need to combine that knowledge to build the animation you want. Now, I will be using Codesandbox because it's a faster setup than just write in VSCode, etc ... But feel free to use whatever you prefer. I will link the codesandbox for every animation, so you can go and check all the code. Also, I want to focus on explaining the code related to the animation, not the React and JS parts, but feel free to ask me anything in the comments.

Animation one

Now, I will go step by step how you can create that animation using useSpring hook. Create a new file called fade.js and copy this code :

import React from "react";
import { useSpring, animated } from "react-spring";

const Fade = () => {
  const [startAnim, setStartAnim] = React.useState(false);
  const props = useSpring({
    to : {opacity: 1},
    from: { opacity: 0 },
    reverse: startAnim
  });
  return (
    <>
      <animated.div
        style={{
          ...props,
          fontSize: "40px"
        }}
      >
        useSpring hook is simple
      </animated.div>
      <button
        style={{
          fontSize: "20px",
          marginTop: "10px",
          textTransform: "uppercase",
          textDecoration: "none",
          background: "#8776e3",
          padding: "20px",
          borderRadius: "5px",
          outline: "none",
          border: "none"
        }}
        onClick={() => setStartAnim((prevState) => !prevState)}
      >
        {`${startAnim ? "fade in" : "fade out"}`}
      </button>
    </>
  );
};
export default Fade;

After that, import it to your main component. Now let's explain the code :

First, import useSpring and animated from React Spring

import { useSpring, animated } from "react-spring";

Second, define your spring: useSpring takes an object with properties inside. In our case, we will use the from property, which takes an object with the initial state of the item you want to animate and the to property is the final state of the animated item. The reverse property allows you to swap the toand from property. You can find more about the API properties in https://www.reactspring.io/docs/hooks/api.

const props = useSpring({
    to : {opacity: 1},
    from: { opacity: 0 },
    reverse: startAnim
  });

Finally, you need to tie the animated values to your view. We are extending the div using animated and then, spread the props.

<animated.div
        style={{
          ...props,
          fontSize: "40px"
        }}
      >
        useSpring hook is simple
      </animated.div>

Animation 2:

I created this animation to explain how and when to use useSprings hook. When you use this hook? If you want to animate similar components with different animations, then this hook is perfect. How does this hook work? It is very similar to useSprings but instead of creating one spring, it creates multiple springs each with its own configuration. So, if you want to animate multiple things, instead of using the useSpring a lot of times, you can create a list with the properties that you want and define all your springs with one hook. After that, map over those springs and spread them in a component. We can go over this one more time in my example. Let's code.

1) Create an array of items with the properties you want to animate:

const items = [
  {
    key: "1",
    content: "i will slide a little",
    from: { transform: `translate(0px)`, color: "black" },
    to: { transform: `translate(60px)`, color: "red" }
  },
  {
    key: "2",
    content: "i will slide backward",
    from: { transform: `translate(150px)`, color: "blue" },
    to: { transform: `translate(0px)`, color: "black" },
    config: { mass: 1 }
  },
  {
    key: "3",
    content: "i will slide more ",
    from: { transform: `translate(0px)`, color: "black" },
    to: { transform: `translate(250px)`, color: "purple" }
  }
];

2) Define your springs, this is where useSprings is helpful. You will see how easy it is to set up all the different animations in a few lines of code.

const springs = useSprings(
    items.length,
    items.map(({ key, content, ...config }) => {
      return {
        ...config,
        reverse: startAnim
      };
    })
  );

useSprings hook takes a number as a first argument which represents the number of animations and a callback function. This is the general form of this hook :

const springs = useSprings(number, items.map(item => ({ opacity: item.opacity }))

3) Finally map over these springs and animate the component you want

      {springs.map((spring, index) => (
        <div
          style={{
            ...spring,
            display: "block",
            textAlign: "left",
            marginTop: "10px",
            border: "solid black"
          }}
        >
          <animated.div
            style={{
              ...spring,
              display: "block",
              fontSize: "20px",
              padding: "10px"
            }}
          >
            {items[index].content}
          </animated.div>
        </div>
      ))}

Animating 3:

To create the animation above we used useTrail hook. It creates multiple springs with a single config. Each spring will follow the previous one. Also, it accepts 2 arguments: The number of items to animate and a single spring configuration. To define your spring you just give the number and the properties as so :

  const springs = useTrail(items.length, {
    from: { transform: `translate(0px)`, color: "black" },
    to: { transform: `translate(250px)`, color: "purple" },
    reverse: startAnim
  });

The rest is similar to what we did before in the previous animations. So, we don't need to go over again.

Animation 4: Mounting and Unmounting components

In this animation, we used useTransition. You use this hook if you want to mount and unmount components. In other words, if you will add or remove a component from the dom tree.

  const spring = useTransition(startAnim, null, {
    from: { transform: `translateX(50px)`, opacity: 0 },
    enter: { transform: `translateX(0px)`, opacity: 1 },
    leave: { transform: `translateX(50px)`, opacity: 0 }
  });

useTransition accepts 3 arguments. The first is a changing state. The second is a function that takes the first argument as a parameter and supposes to return a key. it's null in our case because our first arguments is a boolean. The last argument is an object describing the life cycles.

{transitions.map(
          ({ item, key, props }) =>
            item && (
              <animated.div
                key={key}
                style={{
                  ...props,
                  width: "100vw",
                  fontSize: "60px"
                }}
              >
                This component will removed
              </animated.div>
            )
        )}

useTransition returns an array of objects that consist of item, key, and props. props are the same as we have in the other hooks, they contain the animation values. key helps you to render a list of component and item refers to the index of the item in the first argument.

Animation 5: Chaining animations

This is the last example and it is created to explain the useChain hook. First of all, and before explain how to use it, you need to be familiar with the 4 other hooks by now because that knowledge will make what we are going to explain looks easier.

useChain will make you able to chain animations and set their order. So, if you have 2 animations, you can chain them together and put their order. For example, you are telling the component, first, you need to rotate and then fade away.

Let's explain the interesting part of the code and the steps you need to chain your animations:

1) Make sure to import the useChain hook.

2) Define your animations like usual, however, you need to catch it's reference and we will use useRef hook for that:

const springRef = useRef();
  const spring = useSpring({
    to: { opacity: 1 },
    from: { opacity: 0 },
    reverse: !startAnim,
    ref: springRef
  });

3) once you define your animations and catch their refs, you will need to run useChain. This hook will accept an array of refs to determine the order of execution. In my animation, there is a button where I want to reverse the order of the animation, so, I will use a ternary.

useChain(
    startAnim ? [springRef, trailSpringsRef] : [trailSpringsRef, springRef]
  );

Thank you for your time and I hope you get the hang of it ;)