Passing data from page to layout
Answered
Netherland Dwarf posted this in #help-forum
Netherland DwarfOP
Hey! Quick question, I'm trying to pass a string to my layout. I know this is typically frowned upon, but I'm trying to add a back button on the navigation bar, which is rendered on the layout. This back button is only visible on certain routes and passes the url to redirect to on the layout. Is there any way to do this on the server? I used a context to manage this data, but since I'm using a mix of server and client components there is a delay and shifts the DOM once loaded
Answered by B33fb0n3
yes it is possible with server side context like cookies or url or ... incl. server action or route handlers or ... However: this is mostly complicated. It's an interactive element on your site and everything that you said can be waaay easier be archive than using anything serverside
Easier way (clientside): https://nextjs-forum.com/post/1314091270037311518#message-1314225926128668734
Easier way (clientside): https://nextjs-forum.com/post/1314091270037311518#message-1314225926128668734
35 Replies
Netherland DwarfOP
For example, the first screenshot needs a back button.
The second doesn't because it renders the menu by default
My current idea is implementing cookies that would handle this for me
@Netherland Dwarf Hey! Quick question, I'm trying to pass a string to my layout. I know this is typically frowned upon, but I'm trying to add a back button on the navigation bar, which is rendered on the layout. This back button is only visible on certain routes and passes the url to redirect to on the layout. Is there any way to do this on the server? I used a context to manage this data, but since I'm using a mix of server and client components there is a delay and shifts the DOM once loaded
yes it is possible with server side context like cookies or url or ... incl. server action or route handlers or ... However: this is mostly complicated. It's an interactive element on your site and everything that you said can be waaay easier be archive than using anything serverside
Easier way (clientside): https://nextjs-forum.com/post/1314091270037311518#message-1314225926128668734
Easier way (clientside): https://nextjs-forum.com/post/1314091270037311518#message-1314225926128668734
Answer
@B33fb0n3 yes it is possible with server side context like cookies or url or ... incl. server action or route handlers or ... However: this is mostly complicated. It's an interactive element on your site and everything that you said can be waaay easier be archive than using anything serverside
Easier way (clientside): https://discord.com/channels/752553802359505017/1314091270037311518/1314225926128668734
Netherland DwarfOP
What can I do alternatively?
The other option I know would be making a useContext and the issue I had with that is a small delay when it rendered the content
@Netherland Dwarf What can I do alternatively?
Doing it clientside. The „back“ functionality is just „router.back()“ and to get the route (or path) you can use the hook „usePathname“. With that the button is only visible in some routes. So no need for a special context or anything. Then just directly render the button instead of hiding it by default. It will then still be rendered via SSR, but hydrated on client
@B33fb0n3 Doing it clientside. The „back“ functionality is just „router.back()“ and to get the route (or path) you can use the hook „usePathname“. With that the button is only visible in some routes. So no need for a special context or anything. Then just directly render the button instead of hiding it by default. It will then still be rendered via SSR, but hydrated on client
Netherland DwarfOP
Oh okay interesting, but wouldn’t that require me to manually type specific routes that would need to have this functionality with the usePathname?
Barbary Lion
I would do it with parallel routes, I did it with breadcrubs inside my layout for every child page.
@Netherland Dwarf Oh okay interesting, but wouldn’t that require me to manually type specific routes that would need to have this functionality with the usePathname?
Yes, you can create for example an array that contains all the needed routes. However: in any other case you need to „define“ this routes as well. So yes, that’s a required step
@Barbary Lion I would do it with parallel routes, I did it with breadcrubs inside my layout for every child page.
Netherland DwarfOP
I just read the documentation for that, interesting concept I never used it before, looks like a fun thing to try honestly
@Barbary Lion I would do it with parallel routes, I did it with breadcrubs inside my layout for every child page.
Of course you can do all that via the server technically, but you might do complex things that are harder to maintain or just over complicated
@B33fb0n3 Yes, you can create for example an array that contains all the needed routes. However: in any other case you need to „define“ this routes as well. So yes, that’s a required step
Netherland DwarfOP
Fun fun, is there anything I’d need to do to implement the router so I can access the router.back? Or is this accessible out of the box
@Netherland Dwarf Fun fun, is there anything I’d need to do to implement the router so I can access the router.back? Or is this accessible out of the box
The „useRouter“ hook (where the router comes from) is a nextjs hook. You don’t need to do anything to get this (just import)
Btw.: when you would use parallel routes you need to define the same array 😉
Btw.: when you would use parallel routes you need to define the same array 😉
@B33fb0n3 The „useRouter“ hook (where the router comes from) is a nextjs hook. You don’t need to do anything to get this (just import)
Btw.: when you would use parallel routes you need to define the same array 😉
Netherland DwarfOP
Ah okay, wouldn’t that require me to make the layout a client component?
And yeah I figured 😅
And yeah I figured 😅
Oh nvm
@Netherland Dwarf Ah okay, wouldn’t that require me to make the layout a client component?
And yeah I figured 😅
Not really. Exclude it into its own component
Netherland DwarfOP
I have a component within the layout that is a client
But thanks man, I appreciate it
@B33fb0n3 Not really. Exclude it into its own component
Netherland DwarfOP
Wait one more thing, in the second screenshot I showed earlier, it goes back to the previous questionnaire question, I currently don’t change the URL so it people can’t just go to questions and I don’t have to verify them accessing it. What can I do in this case?
Another question I had, I know using router.back implicitly goes back to whatever the previous route was, what if I wanted to have them be redirected to the route I want them to without having that issue, it seems like I might have to define both the route and the back route honestly
Another question I had, I know using router.back implicitly goes back to whatever the previous route was, what if I wanted to have them be redirected to the route I want them to without having that issue, it seems like I might have to define both the route and the back route honestly
@Netherland Dwarf Wait one more thing, in the second screenshot I showed earlier, it goes back to the previous questionnaire question, I currently don’t change the URL so it people can’t just go to questions and I don’t have to verify them accessing it. What can I do in this case?
Another question I had, I know using router.back implicitly goes back to whatever the previous route was, what if I wanted to have them be redirected to the route I want them to without having that issue, it seems like I might have to define both the route and the back route honestly
You shouldn’t handle a multi step form (setup process) though the url. It’s the same here: yes, it is possible doing that, but it’s over complicated (as you see now on your question). A multi step (input) form is mostly only interactive. So create a client component. It’s fine to have client components. Then replace this „back“ button to a button that just switches back to the previous step
@B33fb0n3 You shouldn’t handle a multi step form (setup process) though the url. It’s the same here: yes, it is possible doing that, but it’s over complicated (as you see now on your question). A multi step (input) form is mostly only interactive. So create a client component. It’s fine to have client components. Then replace this „back“ button to a button that just switches back to the previous step
Netherland DwarfOP
That was my original plan having it on the multi step form, but if you look on the second screenshot I noticed that the position I want it to be at is the navigation bar in the top. I didn’t know how I’d be able to put this component in the layout container without using an absolute position, even then I don’t know how I can get it exactly positioned right in the container
I just had an idea, what if I have multiple children in my component. The second child would have some random html, and in the layout I can check whether this is supplied, if this is maybe I can either pass a key that contains the back url and access that on the layout if it requires a specific button, I can just pass the button as the html
Wow that was a lot of information. Do you have a repo or repro where I can see your code? That would help a lot to put the correct components at the correct locations
@B33fb0n3 Wow that was a lot of information. Do you have a repo or repro where I can see your code? That would help a lot to put the correct components at the correct locations
Netherland DwarfOP
If I'm being honest, I haven't uploaded my code to a repo yet because I haven't had time, but I can show you what everything looks like real quick
This is what my file directory looks like, the profiles/create need to have a back button
This is what my file directory looks like, the profiles/create need to have a back button
This is what the design looks like for the back button
This is the dashboard, you can't see the back button but instead the menu
This is what my layout looks like
import Logo from "@/public/imgs/logo.png"
import Image from "next/image";
import { getDashboardUser } from "@/lib/server/user/getDashboardUser";
import { ServerProps } from "@/lib/types/Server";
import { SidebarMenu } from "./_components/nav/SidebarMenu";
import { DashboardLayoutClient } from "./_components/layout/layout";
export default async function DashboardLayout(props: ServerProps) {
const user = await getDashboardUser();
return (
<div className="">
<div className="flex h-svh">
<aside className="hidden lg:flex px-5 pt-5 pb-4 flex-col gap-10 min-w-[170px] ">
<Image className="w-[40px] h-auto" src={Logo} alt="AthleticScholar Logo" width={50} height={50} />
<div className="flex-1 flex flex-col justify-between">
<SidebarMenu heading="Menu" menu={[{ 'page': "Dashboard", 'icon': "dashboard", isActive: true }, { page: "Profiles", icon: "profiles" }, { page: "Messages", icon: "inbox" }]} />
<SidebarMenu heading="Other" menu={[{ 'page': "Settings", 'icon': "settings" }, { page: "Log out", icon: "logout" }]} />
</div>
</aside>
<div className="flex flex-col px-5 pt-5 pb-4 flex-1 gap-6 overflow-auto">
<DashboardLayoutClient user={user} />
<main className="flex-1 lg:px-6 lg:py-6 lg:bg-secondary lg:border lg:border-border lg:rounded-xl">
{props.children}
</main>
</div>
</div>
</div>
)
}
This is the DashboardLayoutClient, mind you this is a client component
export function DashboardLayoutClient({ user }: Props) {
return (
<>
<div className="hidden lg:flex lg:justify-between">
<div className="flex gap-5">
<Image className="rounded-full object-cover h-[45px] w-[45px]" src={user?.image} alt={`${user.name}'s Thumbnail`} width={45} height={45} />
<div className="flex flex-col gap-1">
<h1 className="font-medium text-base tracking-tight">{user.name}</h1>
<span className="text-sm text-text-secondary">Athlete</span>
</div>
</div>
<div>
<NotificationButton />
</div>
</div>
<DashboardMobileLayout />
</>
)
}
and lastly
My profiles/create page
export default function CreateProfile() {
const [step, updateStep] = useState(1)
return (
<Wrapper>
<StepperWithHeader className=" lg:w-full lg:top-[20px]" amount={3} current={step} >
<span className="text-sm text-text-label lg:text-center"><span className="text-white">Step {step}</span> out of 3</span>
</StepperWithHeader>
<PageHeading heading="Build Your Winning Profile" subheading="Craft your profile with the details that make you an attractive recruit" />
</Wrapper>
)
}
ok and where exactly is now the problem in wrapping them correctly?
As you see, that's a lot of effort right now, so the best for me as well as for you is to create a repo
As you see, that's a lot of effort right now, so the best for me as well as for you is to create a repo
Netherland DwarfOP
All good, ended up just making a component for my layout!