DEV Community

Kuba
Kuba

Posted on

Different approach to loading screen in React

Most of the loading screens I saw, based on boolean variable loading. Then based on it, component loadingScreen is returned or the actual page. The more data I wanted to load, the more if statements I had to make to check if I am still loading. More such ifs sounds like a bad idea to me 🤷‍♀️.

I wanted to make my LoadingScreen component smart enough to figure out, if it should be still displayed.

Let's keep loading screen simple for this example. If it has children, display them. Else, use default loader.

// LoadingScreen.js
const LoadingScreen = (props) => {
return (
        <div class="bg-gray-600 h-screen w-screen fixed">
            {
                props.children? (
                    <div>
                        {props.children}
                    </div>
                ):(
                    <div>Default loader...</div>
                )
            }
        </div>
    )
}

Enter fullscreen mode Exit fullscreen mode

Since loader has to decide if data is already loaded, it needs to have access to those data. From the main component point of view it will look like this.

// MainPage.js
const MainPage = (props) => {
    const [data, setData] = useState(undefined);

    useEffect(() => {
        if(typeof props.data !== 'undefined'){
            var keyValuePairs = Object.values(props.data).map((key) => <li key={key}>{key}</li>);
            setData(keyValuePairs);
        }else{
            props.makeRequest();
        }
    }, [props.data])

    return (
        <>
            <LoadingScreen toLoad={[data]}/>
            <div>
                <h2>Conent:</h2>
                <div>
                    {data}
                </div>
            </div>

        </>
    )
}

const mapStateToProps = (state) => {
    return {
        data: state.main.data
    }
}

const mapDispatchToProps = dispatch => ({
    makeRequest: () => dispatch(getData());
})

Enter fullscreen mode Exit fullscreen mode

The simplest way of checking if data is already loaded, is checking if all elements in array toLoad are not undefined.

Let's add such check to LoadingScreen component.

// LoadingScreen.js
const LoadingScreen = (props) => {

    const isDataLoaded = () => {
        for(var i in props.toLoad){
            if(typeof props.toLoad[i] === 'undefined'){
                return false;
            }
        }
        return true;
    }

    return (
        isDataLoaded() ? (
            null
        ):(
            <div class="bg-gray-600 h-screen w-screen fixed">
                {
                    props.children? (
                        <div>
                            {props.children}
                        </div>
                    ):(
                        <div>Default loader...</div>
                    )
                }
            </div>
        )
    )
}

Enter fullscreen mode Exit fullscreen mode

And that's it! LoadingScreen will be displayed till data will stay undefined. Another approach is to check if data is equal to it's initial state.

// MainPage.js
<LoadingScreen toLoad={[data]} toLoadInitialState={[initialData]}/>
Enter fullscreen mode Exit fullscreen mode

And the check will be:

// LoadingScreen.js 

const isDataLoaded = () => {
    for(var i in props.toLoad){
        if(props.toLoad[i] === props.toLoadInitialState[i]){
            return false;
        }
    }
    return true;
}
Enter fullscreen mode Exit fullscreen mode

Of course the problem will be when obtained data will be equal initial data but in most of my cases it does the job.

It is about one month since I started to learn React so feel free to point out any rookie mistake I made 😉.

Top comments (6)

Collapse
 
horaceshmorace profile image
Horace Nelson • Edited

I'm not sure why you'd need to check individual data points to know whether data has loaded. You're conflating: (1) checking whether data has been loaded, and (2) checking whether the data is valid (contains all expected properties).

I think you've come up with an incomplete pattern for data validation. You'd need to add in some checks for data types and value constraints rather than only checking whether a property exists. However, to simply check whether data has been loaded, all you really need to know is whether your method for loading the data (or, usually, fetching the data) has completed or not.

It's important to understand that the question of whether data has been loaded is a different question from whether data is valid.

Here's an example of a solid React + Redux implementation I threw together: codepen.io/HoraceShmorace/pen/QWpxLYw. It determines whether data is loading in a loadData Redux action, and determines whether data is valid in a setData Redux action.

Collapse
 
kuba_szw profile image
Kuba

Thanks for your example. I thought it over again and you are totally right. Proper validating data in loading screen component leads to as much 'if's' as cheking if the data is loaded in parent component and should be separate from checking if fetching is finished.

I was trying to find a way of checking if fetching is finished with Promisse.all( ) but your solution with two Redux actions is much simpler and cleaner 😉.

I think it is a good idea to extend this post with your solution. Whould you like to make your own post about it and I will link to it? I can sum up your solution below this one too.

Collapse
 
horaceshmorace profile image
Horace Nelson • Edited

You don't really need 2 Redux actions. I really just used a second one to make it easier to simulate invalid data. The point here is that: (1) checking that your data has loaded and (2) checking that the data is valid are two different things, both of which you should do, but not at the same time.

Here's a slightly different example that illustrates a better pattern codepen.io/HoraceShmorace/pen/yLMqOVr. Note the validateData function, how validation was moved into the loadData async action, and that the setData async action was removed entirely.

Collapse
 
teja463 profile image
Brahma Teja Ponnuru • Edited

What if the backend returns an error. Then the data will be undefined still, in this case the loader will be shown indefinitely.

Collapse
 
kuba_szw profile image
Kuba

I would catch this error and pass it to the state. Then handle it only in LoadingScreen component. Add some message on loadingScreen that something went wrong or redirect. What do you think? 😉

Collapse
 
teja463 profile image
Brahma Teja Ponnuru

Yeah nice idea.