When developing a webpage on the frontend, it is inevitable that we need to do some communication with the server, that is the backend.

For the website I developed, I used the LoadingPage.tsx component to show the user a loading screen when the user directs to a new page. This enhances user experience as the user has something to look at while the contents are being loaded from the server.

Here is what the LoadingPage.tsx looks like, as you can see it is very simple, only returning a component that contains a rotating loading icon.

export default function LoadingPage() {
    return (
        <div className="flex justify-center">
        <div className="mt-10"><i className="fa-solid fa-spin fa-rotate-right text-3xl"></i></div>
        </div>
    )
}

Inside a page component, I add a React state called “loading”, and set it to True. When a user accesses the page, “loading” state will be True.

export default function MarketPage() {
    const [loading, setLoading] = useState<boolean>(true); // Track loading state
}

When some kind of new content needs to be loaded, loading is set to True again, even if it finished loading.

    useEffect(() => {
        setLoading(true);
        setPostList([]);
        setCurrentPage(1);
        setHasMore(true);
        loadPosts();
    }, [postStatusOption, postCategoryOption, negotiabilityOption, orderOption, buySellOption])

The loadPosts() function is the function that communicates with the server.

    const loadPosts = (newPage = 1) => {
        axios.get(`${process.env.REACT_APP_HOST_NAME}/api/post/market-post?page=${newPage}`, 
            {
                params: {
                    page: newPage,
                    postStatusOption,
                    postCategoryOption,
                    negotiabilityOption,
                    orderOption,
                    buySellOption,

                }
            })
            .then((response) => {
                const responseData = JSON.parse(response.data);
                setPostList((prevPosts) => [...prevPosts, ...responseData]); // Append new posts to existing list
                setCurrentPage(newPage); // Update current page
                if (responseData.length < 10) {
                    // If we get fewer than 10 posts, there are no more posts to load
                    setHasMore(false);
                }
            }).catch((error) => {
                console.log(error);
                setServerError(true);
            }).finally(() => {
                setLoading(false);
                setExtraPostLoading(false);
            })
    }

In the finally block of then, catch, finally, I set loading state to false, so regardless of a error or a successful request the loading will become false and a appropriate page will be shown.

Here is the component code that stops the user from viewing the page when something is still loading:

    if (loading) {
        return <LoadingPage></LoadingPage>
    }
    if (serverError) {
        // change to server error page.
        return <NotFoundPage></NotFoundPage>
    }
    return (
        <section>
            <FilterBar></FilterBar>
            {postList.length === 0 ? <ZeroPostsPage></ZeroPostsPage> :
                <>
                    <PostList postList={postList}></PostList>
                    <div className="flex justify-center">
                        {hasMore && !loading && !extraPostLoading && (

                            <Button customClass="p-2 bg-purple-500 hover:bg-purple-600" buttonText="Show more" handleButtonClickProp={handleShowMoreClick}></Button>

                        )}
                        {extraPostLoading && (
                            <i className="fa-solid fa-spin fa-rotate-right text-3xl m-2"></i>
                        )}
                    </div>
                </>
            }

        </section>
    )

Notice that LoadingPage comes before the actual components, so if loading state is true the page contents won’t be shown.