Reputation: 90
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;
Upvotes: 0
Views: 1108
Reputation: 51
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.
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}>
Upvotes: 2