The Easiest Way to Animate a Loading Spinner 
Tags: animations, react, scss, svg
Published: 2021-02-28 15:52:01

While on a quest to learn how to build some of the most commonly requested animations by designers, the loading spinner seems like a rite of passage.

This time around, I wanted to see if I could [use the awesome power of svgs](https://dev.to/singhshemona/breaking-down-svgs-1201) to draw out a circle then animate that circle. This could be a lot cleaner than attempting to animate borders or place rotating circles on top of other circles in CSS. 

We will be building today's spinner here with React. Thinking in terms of states, there are two main ones. We are either:
1. Waiting for something - show the spinner
2. That something has happened - no longer show the spinner

To make this feel more realistic, we will have the spinner wait for a response from the Fetch api. There are plenty of open apis for us to request from for the sake of this tutorial.

Take a look at the set up for our component.
```typescript

import React, { useState, useEffect } from 'react';
import './Loading.scss';

export const Loading = () => {
  const [loading, hasLoaded] = useState(false);

  useEffect(() => {
    const timer = setTimeout(() => {
      fetch('https://jsonplaceholder.typicode.com/posts')
        .then((response) => response.json())
        .then((json) => {
          hasLoaded(true);
        });
    }, 1100);

    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="spinner-container">
      {loading ? (
        <p>Content has loaded!</p>
      ) : (
        <svg className="spinner" role="alert" aria-live="assertive">
          <circle cx="30" cy="30" r="20" className="circle" />
        </svg>
      )}
    </div>
  );
};
```

Let's walk through what's going on here.
1. First, we set up the two states I mentioned at the beginning. The only two states the spinner can be in: either we are waiting for something to happen, or it has already happened. A simple boolean does the trick.
2. The handy `useEffect` hook is where we can handle what it is that we're waiting for. It's likely you'll be waiting for some data to return, so I've set up a sample fetch request. You may also notice I have it wrapped inside of a `setTimeout`. This is because the information comes far too fast for us to see the spinner in action, so for the purposes of delaying our response I've added a `setTimeout` that you're welcome to adjust in order to see the spinner for longer. I have it set to 1100 milliseconds so that we can see the spinner for at least a second. In reality, you might not need a `setTimeout` since the data you'll be requesting will likely take it's own time.
3. In the return of the `useEffect`, I clean up the `setTimeout` like the responsible developer I am. 😇
4. Now for the actual component. We have one `div` that holds everything. Inside, we set our two states: If the content has loaded already, print something that tells us this. If the content has not yet loaded, this is where we render our animated spinner.
5. The spinner is a simple `circle` tag wrapped inside of an `svg` tag. We define some attributes like height and width, as well as those that will make it accessible like `aria-live` and `role`.

Ok! We have the skeleton of a spinner. But, there's nothing to see yet. The styles are where the actual magic happens. Let's take a look at them:

```scss
.spinner-container {  
  .spinner {
    transform: rotate(-90deg);
    width: 60px;
    height: 60px;
  
    .circle {
      stroke-linecap: round;
      stroke-dasharray: 360;
      stroke-width: 6;
      stroke: blue;
      fill: transparent;
      animation: spin .6s ease-in-out 0s normal infinite;
    }
  }
  
  @keyframes spin {
    from {
      stroke-dashoffset: 360;
    }
    to {
      stroke-dashoffset: 40;
    }
  }
}
```
Now, let's walk through the styles.
1. We have the `.spinner-container` wrapped around everything. Pretty straightforward.
2. The `svg` gets a class of `.spinner` with height and width specified as well as the rotation that will occur while being animated.
3. The `.circle` class is where I first define some stylistic qualities to the actual circle and then the `animation` property is the key to it's movement. I set it to be the keyframe animation named `spin`, which is simply pulling the filling of the circle forward.

Here is what it all looks like in action. Be sure to hit the 'rerun' button on the bottom right.

{% codepen https://codepen.io/singhshemona/pen/bGBaZYz %}

Voila! Just a few lines of scss to make the spinner come to life. Years ago before I knew this handy tactic of manipulating and animating the fill of svgs, I had built a different spinner. It used bulky, confusing styles to make the drawing of the border for a circle div seem fluid. 

Makes you question coding patterns you might be unconsciously following now that could be done more efficiently. 🤔