React Loading Screen Tactics — Improving User Experience

Dan Halperin
Frontend Weekly
Published in
5 min readJul 1, 2019

If your application gives the user a good feeling, they are more likely to continue using it.

Loading screens are a good place to start our journey of improving the feel of our applications. In the example above we are fetching data from three separate API’s before displaying the welcome screen. In the “before” loading screen, we are leaving the user in the dark. Whatever processes are running in the background are completely hidden from the user. In the “after” loading screen, we show the user what’s going on behind the scenes, then give a positive confirmation when each process finishes. The user feels they are part of the process, and it feels good.

Let’s see how we can spice up our loading screens, step by step.

Create a new app

npx create-react-app reactuxmedium
cd reactuxmedium

Install packages for animations & fading

npm i react-loading react-lottie react-fade-in bootstrap

Start app

npm start

Build simple loading screen

Head over to src/App.js and delete everything in the <header></header> tag and replace the contents with a <Loading /> component. Then import the Loading module from ./loading.js (we will create this in the next step):

import Loading from "./loading.js"

src/App.js should now look like this:

Now create a new file in the src folder and name it loading.js

Let’s import the following (bootstrap and a simple react loader):

import React from "react";import FadeIn from "react-fade-in";import Lottie from "react-lottie";import ReactLoading from "react-loading";import "bootstrap/dist/css/bootstrap.css";

Now we can create our Loading component:

export default class Loading extends React.Component {
constructor(props){
super(props)
this.state = {
done: undefined
}
}
render(){
return(
<h1>hello world</h1>
)
}
}
Our app should now look like this.

Now let’s replace the <h1></h1> with a react loader if this.state.done is false:

render() {
return (
<div>
{!this.state.done ? (
<ReactLoading type={"bars"} color={"white"} />
) : (
<h1>hello world</h1>
)}
</div>
)
}
Loading forever.

Now we need to make an API call and set the state.done to true once it has finished:

componentDidMount() {setTimeout(() => {fetch("https://jsonplaceholder.typicode.com/posts").then(response => response.json()).then(json => this.setState({ done: true }));}, 1200);}render() {
...
Renders our content after API call completes.

We have built a simple loading screen! This is how loading.js should look:

Improve the loading screen

There are several improvements we will make to our loading screen.

  • Tell the user which API call we are currently making.
  • Give a confirmation animation when the API call is complete.
  • Use FadeIn to create smooth transitions.

For more flexible animation choices, we are using react-lottie. You can search for your favorite animation to use at LottieFiles. Let’s replace our current react loader with a lottie file animation. Go ahead and download the lego loader JSON here (or choose one you like), Then place the JSON file in your src folder and rename it legoloading.json.

Now we import the JSON in loading.js :

import * as legoData from "./legoloading.json";

Initialize the options for our animation:

...
import * as legoData from "./legoloading.json"
const defaultOptions = {loop: true,autoplay: true,animationData: legoData.default,rendererSettings: {preserveAspectRatio: "xMidYMid slice"}}export default class Loading extends React.Component {
...

Now replace

<ReactLoading type={"bars" color={"white"} />

With

<FadeIn>
<div class="d-flex justify-content-center align-items-center">
<h1>fetching pizza</h1>
<Lottie options={defaultOptions} height={120} width={120} />
</div>
</FadeIn>
Just needs a confirmation animation!

The last step is to switch the lego animation to a success animation when this.state.done is true. But wait, we already have an action on this.state.done, we are switching to “hello world” when the api call is complete. This means we will not be able to see the success animation. To fix this we will create a separate this.state.loading for when the API call is complete, then set a short timeout before activating this.state.done:

this.state = {
loading: undefined,
done: undefined
};

And change our componentDidMount function:

componentDidMount() {
setTimeout(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then(response => response.json())
.then(json => {
this.setState({ loading: true });
setTimeout(() => {
this.setState({ done: true });
}, 1000);
});
}, 1200);
}

Perfect, now we can switch out our success animation. Download the lottie file here, place it in src directory, and rename it to doneloading.json

Now import it as doneData:

import * as doneData from "./doneloading.json";

And create a defaultOptions2, notice that for this animation we set loop to false:

const defaultOptions2 = {
loop: false,
autoplay: true,
animationData: doneData.default,
rendererSettings: {
preserveAspectRatio: "xMidYMid slice"
}
};

Now we can add the success animation when this.state.loading is true:

<FadeIn>
<div class="d-flex justify-content-center align-items-center
<h1>fetching pizza</h1>
{!this.state.loading ? (
<Lottie options={defaultOptions} height={120} width={120} /
) : (
<Lottie options={defaultOptions2} height={120} width={120} />
)}
</div>
</FadeIn>
Final Result

This is how our completed loading.js should look:

You can download the full project on the Github

For more React UX

--

--