Creating Skeleton Loading Animation in React
Tags: javascript, react, webdev, beginners
Published: 2022-10-16 15:00:55

# Introduction

Loading screens are an important aspect for any application. This lets the user know that the processing is going on. There are lots of evolution in the loading screen. We have moved from the simple `Loading….` message to the more advanced Skeleton Loading Animation.

Skeleton Loading animation is a more advanced loading animation and its looks dope. You have seen it before on YouTube and other platforms. 

Today, we are going to create a Skeleton Loading Animation in React with the `react-loading-skeleton` library. It is one of the most used libraries for creating skeleton loading animation with a single component. 

In the end, we will be able to achieve the below output for our loading screen.

![LoadingSkeleton](https://paper-attachments.dropbox.com/s_C0F2FC4C3E0A45AFB52BB1D79D3292EA0BA0141526EA773B043CAEBB61F31E62_1665574094455_ezgif.com-gif-maker.gif)

So, let’s get started.

# Setting Up the Environment

For creating React app, we have used Vite instead of CRA. Vite creates a react application with minimal already created files and code. This is quite fast in comparison with CRA. You can start by running the following command in the terminal:

```bat
    npm create vite@latest
```
After this, entered the name of the project in the terminal. I have used the `skeleton-loading-react` as the name. After hitting enter, choose the framework as `React`.  Lastly, choose the programming language for the framework between JavaScript and TypeScript.
This will create the react application instantly. Change the directory to `skeleton-loading-react` and run `npm install` in the terminal to install the packages. 
Additionally, we need to install the skeleton loading animation. Run the below command in the terminal:

```bat
    npm i react-loading-skeleton
```

## Other dependencies I have used
- [Axios](https://axios-http.com/docs/intro): For making calls to the API
- [Chakra UI](https://chakra-ui.com/): For building the component


## What are we building?

We are going to use the [MovieDB](https://developers.themoviedb.org/3) API to fetch the trending movies and display them in the card component. While making the call, we are going to display our Loading Skeleton.


# App.js

Let’s build the project with one component at a time. Starting with the first component `App.js`. Let’s look into the code then I explain it.

```jsx
    import { useState, useEffect } from 'react'
    import './App.css'
    import  axis from 'axios'
    import AnimeCard from './components/AnimeCard'
    import {Grid} from '@chakra-ui/react'
    import LoadingSkeleton from './components/LoadingSkeleton'
    
    function App() {
      const [loading, setLoading] = useState(true) //state for loading
      const [data, setData] = useState() // data is extracted from the API
      const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // array for number of loading skeleton
      useEffect(() => {
        let timerId;
        if (loading) {
          timerId = setTimeout(async () => {
            await axios.get(`https://api.themoviedb.org/3/trending/movie/week?api_key=${import.meta.env.VITE_MOVIEDB_KEY}`)
            .then(res => {
              setData(res.data.results)
            })
            setLoading(false)
          }, 2000);
        }
        return () => clearTimeout(timerId);
      }, [loading])
      return ( 
        <div className="App">
          <h1>Trending Movie List</h1>
          <div className='container'>
            {loading && 
              <Grid templateColumns='repeat(4, 1fr)' gap={6}>
                {
                  arr.map(item => {
                    return  <LoadingSkeleton/>
                  })
                }
            </Grid>  
            }
            {
              !loading && 
              <Grid templateColumns='repeat(4, 1fr)' gap={6}>
                {data && data.map((item, index) => {
                  return <AnimeCard name={item.original_title} img={item.poster_path} genre_id={item.genre_ids[0]} />
                })}
              </Grid>        
            }
          </div>
        </div>
      )
    }
    export default App
```  

At the top, we are importing the necessary modules and libraries. In the App function, we use `useState` to define the variable. The comments explain their purposes. We have used the `useEffect` for making a call to MovieDB’s API using Axios. The function containing code for making a call only runs when the `loading` is set to true which is the default value.
We have also used the `setTimeout` function to delay the calling so that we can see the loading animation. After making the call, we are storing the response in the `data` variable.

In return, we are conditionally rendering the component based on `loading`. If it is true we are loading the `LoadingSkeleton` component otherwise `MovieCard`. 


# MovieCard Component

Creating the final component should be done before creating the loading skeleton. This will give us insight into the loading component. We are creating the card in which the data of the movie will be displayed. We have named the component `MovieCard`. 

Here is the code for the component:

```jsx
    import React, {useState, useEffect} from 'react'
    import axios from 'axios'
    import {Image, Tag, Heading} from '@chakra-ui/react'
    const MovieCard = ({name, img, genre_id}) => {
      const [genre, setGenre] = useState()
      useEffect(() => {
        axios.get("https://api.themoviedb.org/3/genre/movie/list?api_key=1428e09fe38be9df57355a8d6198d916")
        .then(res => {
          let genre_name = res.data.genres.filter(item => item.id === genre_id)
          setGenre(genre_name[0].name)
        },[genre_id])
      })
      return (
        <div className='cardContainer'>
          <div className='cardImg'>
            <Image src={`https://image.tmdb.org/t/p/w500${img}`} />
          </div>
          <div className='tagContainer'>
            <Tag size="md" variant='solid' colorScheme='pink'>
              {genre}
            </Tag>
          </div>
          <div className='tagContainer'>
            <Heading color="white" size="md">{name}</Heading>
          </div>
        </div>
      )
    }
    export default MovieCard
```

In MovieDB API, the movie’s genre comes with a code and for accessing the name of the genre using the code, we are calling the API in the useEffect. The return statement is where we are defining the card for the movie. There is a parent container with the name `cardContainer`. Within1 this we have the Image, Genre name as a tag, and title of the movie. 

You can find the CSS of the component here:

```css
    .container {
      display: flex;
      justify-content: space-between;
      width: 100%;
      max-width: 1200px;
      margin: 1em auto;
    }
    .cardContainer {
      display: flex;
      flex-direction: column;
      cursor: pointer;
      background-color: #272D37;
      border-radius: 10px;
      margin-top: 2em;
      border: 1.5px solid transparent;
    }
    .cardImg{
      margin: 1em;
      border-radius: 1em;
    }
    .tagContainer {
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      color: white;
      padding: 0 1em;
      padding-bottom: 1em;
    }
```

This will result into the card look like this:

![MovieCard](https://paper-attachments.dropbox.com/s_C0F2FC4C3E0A45AFB52BB1D79D3292EA0BA0141526EA773B043CAEBB61F31E62_1665571906856_image.png)

# LoadingSkeleton 

Now it’s time to create the loading skeleton.  The loading skeletons have the structure without the data. We have to create these structures as per our data. We are having an image container, a tag for the genre, and a heading tag with the title. Let’s discuss each component in our card one by one.


## Parent Component

The parent component remains the same as it holds our component. We do not need to recreate this.

## Image Container

We need to create a component with the same resolution as the image. This component will be displayed in place of an actual image while loading. Here is the CSS for my card image:

```css
    .cardImgLoading{
      margin: 1em;
      width: 247px;
      height: 374px;
      background-color: #4a5568;
    }
```

## Genre Tag

I used another container for displaying the genre. Here is the code for CSS:

```css
    .tagContainerLoading{
      margin-left: -12em;
      margin-bottom: 1em;
      width: 50px;
      height: 20px;
      background-color: #D53F8C;
      border-radius: 10px;
    }
```

## Title Container

The title is converted into a block component having a height and width. This will be useful in displaying the loading animation. Here is the code:

```css
    .titleContainerLoading{
      margin-left: -3em;
      margin-bottom: 1em;
      width: 200px;
      height: 20px;
      background-color: #4a5568;
      border-radius: 10px;
    }
```

## Skeleton Component

We now just need to pass the above CSS as the class name in the `Skeleton` component. 

```jsx
    <Skeleton highlightColor='#97a2b5' baseColor='#97a2b5' className='cardImgLoading'/>
```

Here is the description of the used props from `loading-skeleton-react`.

| **Prop**                  | **Description**                                | **Default** |
| ------------------------- | ---------------------------------------------- | ----------- |
| `baseColor?: string`      | The background color of the skeleton.          | `#ebebeb`   |
| `highlightColor?: string` | The highlight color in the skeleton animation. | `#f5f5f5`   |

The overall code of the `LoadingSkeleton` is:

```jsx
    import React from 'react'
    import Skeleton from 'react-loading-skeleton' // importing the skeleton component
    import 'react-loading-skeleton/dist/skeleton.css' // importing the css for the animation
    const LoadingSkeleton = () => {
      return (
        <div className='cardContainer'>
          <Skeleton highlightColor='#97a2b5' baseColor='#97a2b5' className='cardImgLoading'/>
          <Skeleton highlightColor='#97a2b5' baseColor='#97a2b5' className='tagContainerLoading'/>
          <Skeleton highlightColor='#97a2b5' baseColor='#97a2b5' className='titleContainerLoading'/>
        </div>
      )
    }
    export default LoadingSkeleton
```

This will result in the following loading animation:

![LoadingSkeleton](https://paper-attachments.dropbox.com/s_C0F2FC4C3E0A45AFB52BB1D79D3292EA0BA0141526EA773B043CAEBB61F31E62_1665574094455_ezgif.com-gif-maker.gif)


# Live Working

I have created this project in a codesandbox container. You can see it here:

{% codesandbox skeleton-loading-react-v5byqe %}

# Conclusion

We have successfully created a skeleton loading in React with `skeleton-loading-react` libraries. You can explore with the Sandbox and create your own loading skeleton.

I hope, this article has helped in understanding the loading skeleton in your React project. Thanks for reading the article.