Syncing server and client components
Unanswered
Montezuma Quail posted this in #help-forum
Montezuma QuailOP
I have a navbar server component and a breadcrumb client component. When I login the navbar loads first and then the breadcrumb component delays and then loads. When I try to make the breadcrumb component and server component and get the path it doesn’t work properly. What’s the best way to accomplish getting these to be in sync?
8 Replies
American black bear
to fix this you need to make your breadcrumb a server component. to achieve this you can either manually specify the breadcrumb data for each page or use middleware or similar to add a custom header containing the current pathname which you will be able to access on server.
approach 1.
// on each page manually insert breadcrumb data
// app/services/development/page.tsx
export function ServicesDevelopmentPage() {
return (
<Breadcrumbs data={["home", "services", "development"]} />
)
}
however if you want your breadcrumbs to be automatically generated you can also use the middelware approach.
1. create
2. set a custom pathname header which you will be able to access in your server components
3. access the header using a server action or server function
1. create
middleware.ts
in /src
folder NOT app
as it will not work lol2. set a custom pathname header which you will be able to access in your server components
3. access the header using a server action or server function
// /src/middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
// add pathname header
const headers = new Headers(request.headers);
headers.set("x-current-path", request.nextUrl.pathname);
return NextResponse.next({ headers });
}
export const config = {
matcher: [
"/((?!api|_next/static|_next/image|favicon.ico).*)",
],
};
You can then get the header if your breadcrumb is a server component by using next/headers.
import {headers as headersPromise} from "next/headers"
export function getPathname() {
const headers = await headersPromise()
const pathname = headers.get("x-current-path")
return pathname ?? "/"
}
Also be careful when using this approach as it will make your entire route dynamically rendered. To fix this you can make
getPathname
a server action by adding "use server"
to the top of the file.This is if you want them to load in sync, but keep in mind that you are nitpicking here and you could just make it so a skeleton is showing for breadcrumbs while they are loading. Not everything needs to be rendered on the server and displayed instantly as the page loads.
Montezuma QuailOP
To use the skeleton loading approach though wouldn’t it have to be a server component ?
American black bear
no you can conditionally render a skeleton while pathname value is not defined or empty string