Next.js Discord

Discord Forum

How to avoid using useEffect on my Header

Unanswered
Amur catfish posted this in #help-forum
Open in Discord
Amur catfishOP
Hello I've been reading NextJS 14.3 Documentation and following the tutorial.
So far i have problems understanding how to use next/navigation server side to use pathName to populate my Header.
What i wish to do is something like this:
import "./globals.css";
import { poppins} from "./fonts";
import HeaderComponent from '@src/app/components/HeaderComponent';
import FooterComponent from '@src/app/components/FooterComponent';
import { Suspense } from 'react';
export default async function RootLayout({
    children,
}: {
    children: React.ReactNode
}) {
    return (
        <html lang="fr">
            <body className={`bg-custom-main-blue ${poppins.variable}`}>
                <HeaderComponent />
                <main className="flex flex-col max-w-[1440px] m-auto">
                    {children}
                </main>
                <Suspense fallback={<div>Loading....</div>}>
                    <FooterComponent />
                </Suspense>
            </body>
        </html>
    );
}

What i wish to do is use my "fetchHeader" function to populate my header Body and Navbar.
but the thing is the content inside the HeaderBody is meant to change depending on the category and slug we find ourselves in, we access this data via de URL.
usually decomposed like /{category/{slug}.

I wish to populate my header following NextJs 14.3 good practices such as avoid using data fetching in useEffects.
but after reading and reading and trying with GPT i can't seem to figure out if what i want is serverProps, static Props, where do i fetch them, in the layout in each page?
Could someone help me understand how to properly do data fetching server side to have a header that changes on navigationPath Change.
thank you in advance, i've been onto this for about 2 weeks always going back

33 Replies

Amur catfishOP
This is my example fetchFunction:
/**
 * 
 * @param args Current pathname(categorie/formation/home), kwargs optional arguments decided by pathname (slug ) 
 * @returns 
 */
export async function fetchHeaderData(args: string, kwargs?: string): Promise<HeaderData> {
  console.log("Entering Fetch Header Data")
  console.log(kwargs ? `Received Pathname: ${args} Received Slug: ${kwargs}` : `Received Pathname: ${args}`);
  let myData: HeaderData = {
    data: {
      navBarData: {} as NavigationBarData,
      headerContentData: {} as HeaderBodyResponse
    }
  }
  try {
    myData.data.navBarData = await fetchNavigationBarData();
  } catch (error) {
    console.log("Error fetching NavBarData", error);
  } finally {
    console.log("Entered Finally Block for HEADER BODY DATA");
    myData.data.headerContentData = await fetchHeaderBodyData(args, myData.data.navBarData, kwargs);
    console.log("HEADER BODY DATA SUCCEEDED ", myData);
  }
  // console.log("NavBarData", myData.data.navBarData);
  let professionsData: ProfessionsGetAllApiResponseStructure[] = (await fetchData('professions')) as unknown as ProfessionsGetAllApiResponseStructure[]; 
// to be continued...
  return myData;
}

all this logic kinda worked inside a use effect but for a NavBar + header i don't think it's good to do a loop of useEffects, but the fetch itself works.
Sun bear
Do you want to get the pathname of the current page in your header component?

In case yes just do it like this:
https://nextjs.org/docs/app/api-reference/functions/use-pathname

'use client'
 
import { usePathname } from 'next/navigation'
 
export default function ExampleClientComponent() {
  const pathname = usePathname()
  return <p>Current pathname: {pathname}</p>
}
on navigation change
it saves the old pathName
i want to get it for my data Fetching
as the Api query goes like this:
const url = `${API_URL}/${queryParam}/${filteringParam ? filteringParam + '/' : ''}${filteringParam2 ? filteringParam2 + '/' : ''}`;

if we're in "/formations/infirmier"
it'd recognice that from pathName, but pathName idk how to use it on server, to have my header statically generated .
I need the server to bring me the correct "headerBodyData" corresponding to the currentPath name
a header could be any of these 3, uses the same header formula it's just the body that changes:
the params there would be like:
/ -> first one
/categorie/{slug}/ ->second one
/formations/{slug} ->third one
As the header is called in the layout phase, before build time, idk how to approach this
without using useEffect on my header
maybe i'm understanding the approach wrong
Sun bear
Ah now I get your point.

So usePathname is only clientside but you want to fetch it serverside in the header component.

Easiest solution would be to move the header component to the page.tsx I think.

Then you know you are in route /category and can read the [slug]

https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes

You could also create 3 layouts and do it similar.

Maybe you can adjust your header like this

<HeaderComponent data={data} />

And pass the data you fetched
Amur catfishOP
i thought of something like that but that would mean to do Header Calls in Pages everytime instead of the root Layout, seems counter intuitive
i could read maybe /formation, but then how would i get the slug server side and update it?
Sun bear
I dont think it makes a difference if you fetch in layout or pages bit not 100% sure about it.
Amur catfishOP
code scalability and maintanability no? also having many <header> tags? , senior guy didn't want us creating "3 header components"
Sun bear
You can check the link in my prev message

export default function Page({ params }: { params: { slug: string } }) {
  return <div>My Post: {params.slug}</div>
}
What is the content of your header component? A navigation?
Amur catfishOP
i'm confused do i want static params, static props, server props?
@Sun bear What is the content of your header component? A navigation?
Amur catfishOP
<navBar>
and then body changes
you could see that as a "home header" "professions header" "course header"
professions would have header info according to a specific profession
course header to a specific course selected.
they all do their specific queries depending on the parent folder + the dynamic slug
i can do the queries and they work, i just don't know how to do it server side properly instead of passing by many use effects and making everything a client component
it's a single headerLayout tho, it's just the information inside that changes, maybe my structure is wrong and i should have a layout per page? but i'm not sure how to abord this
Page({ params }: { params: { slug: string } })

the spread operator seems to work but ..it feels kinda weird doing it for the header
what would my RootLayout vs the other Layouts should look like?
cuz in all sense it's a general layout like this:
        <html lang="fr">
            <body className={`bg-custom-main-blue ${poppins.variable} ${sofia.variable}`}>
                {/* <HeaderContainer /> */}
                <HeaderComponent />
                <main className="flex flex-col max-w-[1440px] m-auto">
                    {children}
                </main>
                <Suspense fallback={<div>Loading....</div>}>
                    <FooterComponent />
                </Suspense>
            </body>
        </html>
it should change to this?
        <html lang="fr">
            <body className={`bg-custom-main-blue ${poppins.variable} ${sofia.variable}`}>
                    {children}
                <Suspense fallback={<div>Loading....</div>}>
                    <FooterComponent />
                </Suspense>
            </body>
        </html>
sorry for all the questions, i'm just kinda confused over all the props that idk which one to get
Sun bear
I would go with doing query either at page.tsx or creste layouts per main page like /, /category, /formations

And the pass the data you queried

<HeaderComponent data={data} />

or

<HeaderComponent path=/category/${slug} />

You dont have to recreate the header component again and again.

You could also write a component like:

<ContentWrapper path=/category/${slug}>
<div>your content</div>
</ ContentWrapper>

And inside the wrapper do something like

<HeaderComponent path={path}>
<main className=...>
{children}
</main>
Hello sorry, i lost access to my work Discord, and i'm on a week leave so don't have access to that pc (i'm the Post OP).
couldn't check before