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.
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:
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:
npm i react-loading-skeleton
Other dependencies I have used
What are we building?
We are going to use the MovieDB 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.
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:
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:
.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:
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:
.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:
.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:
.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.
<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:
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:
Live Working
I have created this project in a codesandbox container. You can see it here:
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.