简体   繁体   English

所有组件的全局加载屏幕

[英]Global loading screen for all components

I'm using a loading screen for this component, while using fetch.我正在使用此组件的加载屏幕,同时使用 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.如果我在每个组件中使用fetch()方法,我将必须执行与示例相同的加载逻辑,或者是否有更快更简单的方法来显示加载屏幕并在加载所有组件和页面时将其删除。

I'm new to next.js and I'm uing an API with express to load all data to the next.js website.我是 next.js 的新手,我正在使用带有 express 的 API 将所有数据加载到 next.js 网站。

'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 “Next.js”方式

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.由于您正在使用外部 API 并在客户端使用 react 来管理加载 state,因此很难以“Next.js”的方式进行。 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.如果您想以“Next.js”方式执行此操作,则需要在 next.js 服务器上执行 API 调用,使用 getServerSideProps、HTTP 拦截器或您喜欢的任何方法。 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.但是,这似乎不像你在这里尝试做的那样,为此使用两个不同的 api 可以被认为是一种反模式。 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.可以创建一个 LoadingScreen 提供程序,它会删除您每次要显示加载屏幕时遇到的重复代码。 You use the 'useLoadingScreen' hook and use the 'setLoading' method instead of the 'isLoading' variable you were using previously.您使用“useLoadingScreen”挂钩并使用“setLoading”方法而不是之前使用的“isLoading”变量。 I'll be using React usecontext for this as it is a generic solution.我将为此使用 React usecontext,因为它是一个通用的解决方案。 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.但是,如果您使用全局 state 管理库,例如 redux、react-query、jotai 或 swt,请随意使用您各自的库来实现它。

LoadingProvider.tsx 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确保通过将主要组件包装在您的提供商中来相应地更新您的“App.tsx”文件

            <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}>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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