简体   繁体   中英

Global loading screen for all components

I'm using a loading screen for this component, while using fetch.

If I use in every component the fetch() method will I have to do the same loading logic as the example, or is there a faster and easier way to show the Loading Screen and remove it when all components and the page are loaded.

I'm new to next.js and I'm uing an API with express to load all data to the next.js website.

'use client';

import HeaderStyle from './Header.module.scss';
import { LoadingScreen } from '../LoadingScreen/LoadingScreen';
import Link from 'next/link';
import { usePathname } from "next/navigation";
import { useState, useEffect, createRef} from 'react';
import { UrlObject } from 'url';

function Header(): JSX.Element {

    const [data, setData] = useState(null)
    const [isLoading, setLoading] = useState(false)

    useEffect(() => {
        setLoading(true)
        fetch('http://localhost:5000/getNavegation')
          .then((res) => res.json())
          .then((data) => {
                setData(data)
                setLoading(false)


          })
      }, 
    [])

    if (isLoading) return <LoadingScreen />;
    if (!data) return <header></header>;


    return (
        <header id={HeaderStyle.header}>

            <div className={HeaderStyle.logo}>
                <Link href="/" className={HeaderStyle.logoname}>Pedro Alves</Link>
            </div>

            <div ref={menu} className={HeaderStyle.menu}>

            {
            data.map((link: { url: string | UrlObject; name: string}, index: number) => (
                <Link key={index} className={HeaderStyle.link} href={link.url}>{link.name}</Link>
            ))}

            </div>

            <div className={HeaderStyle.toggle_menumobile}>
                <span ref={toggle_menumobile} className="icon-base menu-icon"></span>
            </div>

        </header>
    )

}


export default Header;

The "Next.js" Way

Because of the fact that you are using an external API and using react on the client-side for managing loading state, it will be hard to do it in a 'Next.js' way. If you want to do it the 'Next.js' way, API calls would need to be done on the next.js server, either with getServerSideProps, an HTTP interceptor or whichever method you would like. But, that doesn't seem like what you are trying to do here, and using two different api's for this could be considered an antipattern. So instead, we'll do it the react way.

The "Reacty" Way

One can create a LoadingScreen provider which takes out the repetitive code that you're experiencing every time you want to show the loading screen. You use the 'useLoadingScreen' hook and use the 'setLoading' method instead of the 'isLoading' variable you were using previously. I'll be using React usecontext for this as it is a generic solution. But, if you are using a global state management library like redux, react-query, jotai, or swt feel free to implement it with your respective library.

LoadingProvider.tsx

import React, { createContext, useContext, useState } from 'react'
import LoadingScreen from '...../LoadingScreen/LoadingScreen'';

type LoadingScreenProps = {
    loading: boolean;
    setLoading: (loading: boolean) => void
}

export const LoadingScreenContext = createContext<LoadingScreenProps>({
    loading: false,
    setLoading: () => null,
})
export const useLoadingScreen = () => useContext(LoadingScreenContext)

export const LoadingScreenProvider = ({ children }: { children: React.ReactNode }) => {
    const [loading, setLoading] = useState<boolean>(false)

    if (loading) return <LoadingScreen />

    return (
        <LoadingScreenContext.Provider value={{ loading, setLoading }}>
            {children}
        </LoadingScreenContext.Provider>
    )
}

Make sure to update your 'App.tsx' file accordingly by wrapping the main component with your provider

            <LoadingScreenProvider>
              <Component {...pageProps} />
            </LoadingScreenProvider>

Updated Use Case

'use client';

import HeaderStyle from './Header.module.scss';
import { LoadingScreen } from '../LoadingScreen/LoadingScreen';
import Link from 'next/link';
import { usePathname } from "next/navigation";
import { useState, useEffect, createRef} from 'react';
import { UrlObject } from 'url';
import { useLoadingScreen } from '....../LoadingProvider.tsx'

function Header(): JSX.Element {

    const [data, setData] = useState(null)
    const { setLoading } = useLoadingScreen;


    useEffect(() => {
        setLoading(true)
        fetch('http://localhost:5000/getNavegation')
          .then((res) => res.json())
          .then((data) => {
                setData(data)
                setLoading(false)


          })
      }, 
    [])

    if (!data) return <header></header>;


    return (
        <header id={HeaderStyle.header}>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM