DEV Community

Cover image for LOADING. . . For User Experience
Matthew Palmer
Matthew Palmer

Posted on

LOADING. . . For User Experience

Introduction

If you're familiar with fetch() requests in JavaScript and React, then you've likely used Heroku to deploy your back-end APIs. If you're using the free version, you know that Heroku puts servers to sleep... OFTEN. This can be frustrating for users waiting upwards of 10 seconds for information to display on a webpage -- OUCH! So, how can we solve this problem? If only... there was a way to convey to them "Hey, hold on just one moment while we retrieve some information." ... 🤔

Problem SOLVED!

Now, some of you may have a different approach. Personally, I find this method to be short and sweet. It keeps your code clean and is easily readable.

Let's assume that you have a React application with a products page. Before loading those products, you're using componentDidMount() to call upon a function dedicated to fetching them called fetchProducts().

This might be what that function looks like:

export function fetchProducts(){
    return (dispatch) => {
        fetch('https://your-api-url.com/products')
        .then(resp => resp.json())
        .then(products => dispatch({ 
            type: 'RENDER_PRODUCTS', 
            payload: products
        }))
    }
}   
Enter fullscreen mode Exit fullscreen mode

NOTE: Don't worry if you're confused by what you're looking at. I copied a real example from one of my own projects utilizing Redux. Just know, for this example, the syntax you see isn't too important.

Now, right above return (dispatch) => {, we can apply a loader() function, which can be defined within our fetchProducts() function. See the example below:

export function fetchProducts(){
    const loader = () => { // new function
        const loaderDiv = document.querySelector("div#loader");
        loaderSpan.innerHTML = "FETCHING PRODUCTS . . .";
    }

    return (dispatch) => {
        loader() // new code
        fetch('https://your-api-url.com/products')
        .then(resp => resp.json())
        .then(products => dispatch({ 
            type: 'RENDER_PRODUCTS', 
            payload: products
        }))
    }
}   
Enter fullscreen mode Exit fullscreen mode

Perfect! So now we have the loader() function executing PRIOR to our fetch() request. This is setting the innerHTML of our querySelector selection to "FETCHING PRODUCTS. . .". The next issue is making that disappear when we receive a response from our server. This is easily accomplished by creating a new function called unloader() and executing it within our fetch() request. Check it out:

export function fetchProducts(){
    const loader = () => {
        const loaderSpan = document.querySelector("div#loader");
        loaderSpan.innerHTML = "FETCHING PRODUCTS . . .";
    }

    const unloader = () => { // new function
        setTimeout(() => {
            const loaderSpan = document.querySelector("div#loader");
            loaderSpan.innerHTML = ""
        }, 1000);
    }

    return (dispatch) => {
        loader()
        fetch('https://your-api-url.com/products')
        .then(resp => resp.json())
        .then(unloader()) // New code
        .then(products => dispatch({ 
            type: 'RENDER_PRODUCTS', 
            payload: products
        }))
    }
}   
Enter fullscreen mode Exit fullscreen mode

NOTE: You don't have to set a timeout, but it takes about a second or less for the information to load. Maybe a full second might be overkill. Regardless, I'll leave that approach up to you!

And there we have it! Easy-peasy, right?
If you're interested in seeing this in action, follow this link. This is where I implemented this feature in my own project.

Conclusion

There are extended uses when it comes to fetch() requests. They not only handle response data, but they can execute functions as well through their .then() methods. Isn't asynchronous programming fun? I hope this helps some of you out there on a budget!

Connect with me!

LinkedIn/MatthewPalmer9
Github/MatthewPalmer9
Twitter/@MattPDev

Top comments (1)

Collapse
 
lucastrvsn profile image
Lucas Trevisan

I like to put my "unloader" in finally() hook of promise. Makes more sense to me

Great article!