Issue with routing in Next.Js [beginner]
Answered
Pteromalid wasp posted this in #help-forum
Pteromalid waspOP
hi !
I am someone who used to programm a lot of python, and C++ before that. I am trying to learn typescript with react and next.js and so far, it has been really hard. I believe this is a very beginner's question, but that is why, I apologize.
Knowing this, here is my issue: I want a top menu, using DaisyUI, to navigate through the app. So far, it works. If i press on Home, I go to
my App is in pages.tsx with
I am someone who used to programm a lot of python, and C++ before that. I am trying to learn typescript with react and next.js and so far, it has been really hard. I believe this is a very beginner's question, but that is why, I apologize.
Knowing this, here is my issue: I want a top menu, using DaisyUI, to navigate through the app. So far, it works. If i press on Home, I go to
localhost:3000/home. But if I enter the adress manually, the top menu disappears. I think the issue is the fact I'm not using routing correctly for next.js.my App is in pages.tsx with
"use client";
import TopMenu from "./components/TopMenu";
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./home/page";
import Simulation from "./simulation/page";
import Parameter from "./parameter/page";
var menu = ["home", "simulation", "parameter"];
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<TopMenu tabName={menu} />}>
<Route index element={<Home />} /> {/* Default Route */}
<Route path="home" element={<Home />} />
<Route path="parameter" element={<Parameter name="test" />} />
<Route path="simulation" element={<Simulation />} />
</Route>
</Routes>
</BrowserRouter>
);
}
export default App; my folder's architecture is as shown in the pictureAnswered by @ts-ignore
Nextjs comes with its own router hence you don't need the
react-router-dom84 Replies
Pteromalid waspOP
Finally, my
(Sorry, it was too big to fit in a single post)
components/TopMenu.tsx is import React from "react";
import { useState } from "react";
import { useNavigate, Outlet, NavLink } from "react-router-dom";
interface TopMenuProps {
tabName: string[];
}
const TopMenu = ({ tabName }: TopMenuProps) => {
return (
<div>
<div role="tablist" className="tabs tabs-lifted">
{tabName.map((item) => (
<NavLink
role="tab"
key={item}
to={item}
className={({ isActive }) =>
isActive
? "tab tab-active [--tab-bg:lightblue] [--tab-border-color:blue]"
: "tab"
}
>
{item.charAt(0).toUpperCase() + item.slice(1)}
</NavLink>
))}
</div>
<div className="p-2 mt-2">
<Outlet />
</div>
</div>
);
};
export default TopMenu;(Sorry, it was too big to fit in a single post)
I believe my issue is with Next.JS's routing, because I was checking with chatGPT, and he mentionned the index.tsx, and app.tsx or main.tsx. In the tutorial iw as using, the guy was using react+Vite. I thought I didn't have those so i simply ignored it. But with chatGPT's response, I check on the next.js's doc, and found [this](https://nextjs.org/docs/pages/building-your-application/routing/pages-and-layouts), but I am unsure how to apply it in my case, nor if that is necessary. Maybe it's not working because of something else?
You can follow tutorial by official nextjs team to learn nextjs
but for Nextjs, you need to learn React
and React needs JS
Pteromalid waspOP
Yeah I'm kinda learning all of them at once.. I followed these videos entirely
https://www.youtube.com/watch?v=ZVnjOPwW4ZA
https://youtu.be/SqcY0GlETPk?si=E-3V-6yjpjHZa8Ip
Then I'm building with the docs
https://www.youtube.com/watch?v=ZVnjOPwW4ZA
https://youtu.be/SqcY0GlETPk?si=E-3V-6yjpjHZa8Ip
Then I'm building with the docs
I'm guessing there's a lot to change in my code to make it work with next.js's router, right?
Like maybe the folder's architecture
you need to remove all of react-router-dom for it to work
Pteromalid waspOP
What I find weird, is that I created this project using the doc, to have react with next js, and yet I dont have the architecture as shown [here](https://nextjs.org/learn/dashboard-app/getting-started#folder-structure)
and is the folder structure you got?
Pteromalid waspOP
This, I didn't delete anything
this looks like fresh nextjs project without anything configured
you sure you ran this command?
Pteromalid waspOP
I think I used
npx create-next-app@latest, from https://react.dev/learn/start-a-new-react-projectyeah it creates a fresh project
the command in screenshot is a template to follow the tutorial
Pteromalid waspOP
Oh okay, that's why
So I don't need to start over, I can keep going with what I already have
yes
Pteromalid waspOP
Well, as I am trying to apply the tutorial to my project, it's not that easy, as the SideNav is already done in their project
but If I understood correctly we want to have a layout.tsx which will have a sort of "permanent" layout through the pages, and each pages will be called through it ?
and that's why it's applying the layout everywhere?
What I don't understand, is I don't think they've modified the pages.tsx, so how did it adapt?
(I am looking at this step https://nextjs.org/learn/dashboard-app/creating-layouts-and-pages)
Pteromalid waspOP
Oh wait, I think I get it. WHen you make a folder, it's a Route, and everything that's inside of this folder will use the corresponding layout. SO in my case, I don't want the dashboard in my link, so I should modified the top level layout.tsx, is this correct?
@Pteromalid wasp Oh wait, I think I get it. WHen you make a folder, it's a Route, and everything that's inside of this folder will use the corresponding layout. SO in my case, I don't want the dashboard in my link, so I should modified the top level layout.tsx, is this correct?
Double-striped Thick-knee
do you want your TopMenu to appear in your dashboard?
Pteromalid waspOP
I want my top menu in everypage.
My app will be pretty basic, as it will be a human machine interface.
So I will have 3 tabs at the top: home, parameter and simulation. I want to see all three at all time and use them to navigate through the app
My app will be pretty basic, as it will be a human machine interface.
So I will have 3 tabs at the top: home, parameter and simulation. I want to see all three at all time and use them to navigate through the app
@Pteromalid wasp I want my top menu in everypage.
My app will be pretty basic, as it will be a human machine interface.
So I will have 3 tabs at the top: home, parameter and simulation. I want to see all three at all time and use them to navigate through the app
Double-striped Thick-knee
owh ok, just put your TopMenu inside root layout.tsx and render children below it,
this should be enough
import TopMenu '@/..';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
// Add styles if you want
<div>
<TopMenu />
{children}
</div>
);
}this should be enough
Pteromalid waspOP
But I need to remove the navLink and all the Router stuff too right?
@Pteromalid wasp But I need to remove the navLink and all the Router stuff too right?
Double-striped Thick-knee
yeah, nextjs gives you a Link component that you can use instead of navlink
Pteromalid waspOP
Nice. I need to fix something with a <Body> and I'll see
For some reasons I have an issue with this body, I'm not sure what that is
@Pteromalid wasp For some reasons I have an issue with this body, I'm not sure what that is
Double-striped Thick-knee
you dont need to use html and body tag in nextjs
they are automatically placed by nextjs
Pteromalid waspOP
Oh? But that's the default code here, I didn't add this 😅
Double-striped Thick-knee
is that in the root layout? I thought it was in another file
whats the error
Pteromalid waspOP
uhh I don't know, it just disappear without any changes, maybe that was just VSCode being weird with warnings, it happens sometimes
Double-striped Thick-knee
yeah, happened to me before
Pteromalid waspOP
Okay, Im changing
NavLink to Link and making the appropriate modifications and we will seeDouble-striped Thick-knee
good luck
Pteromalid waspOP
Is there an implemented way to highlight which tab I'm on, or should I use
useState() ?@Pteromalid wasp Is there an implemented way to highlight which tab I'm on, or should I use `useState()` ?
Double-striped Thick-knee
there is a hook,
usePathname. use it to check which path you're on and then highlight the routePteromalid waspOP
Okay it works ! (Outside of the tab highlight)
But I was thinking, since the the page loads through the layout.tsx and I'm using the tabName's array to define the names, could there be a way to pass as an argument the item?
This is my topmenu file
But I was thinking, since the the page loads through the layout.tsx and I'm using the tabName's array to define the names, could there be a way to pass as an argument the item?
"use client";
import React, { useState } from "react";
import Link from "next/link";
const TopMenu = () => {
const tabName = ["home", "parameter", "simulation"];
const [selectedMenu, setSelectedMenu] = useState(-1);
return (
<div>
<div role="tablist" className="tabs tabs-lifted">
{tabName.map((item, index) => (
<Link
role="tab"
href={item}
className={
selectedMenu === index
? "tab tab-active [--tab-bg:lightblue] [--tab-border-color:blue]"
: "tab"
}
>
{item.charAt(0).toUpperCase() + item.slice(1)}
</Link>
))}
</div>
</div>
);
};
export default TopMenu;This is my topmenu file
Double-striped Thick-knee
you can pass it as a prop,
"use client";
import React, { useState } from "react";
import Link from "next/link";
const TopMenu = ({ tabName }: { tabName: string[] }) => {
//rest of the code
}
export default TopMenu;<TopMenu tabName=[] />Pteromalid waspOP
Hmm I see thanks ! I also tried your suggestions with pathname and it works great !
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
const TopMenu = () => {
const tabName = ["home", "parameter", "simulation"];
const pathname = usePathname();
console.log(pathname);
return (
<div>
<div role="tablist" className="tabs tabs-lifted">
{tabName.map((item, index) => (
<Link
role="tab"
href={item}
className={
pathname.slice(1) === item
? "tab tab-active [--tab-bg:lightblue] [--tab-border-color:blue]"
: "tab"
}
>
{item.charAt(0).toUpperCase() + item.slice(1)}
</Link>
))}
</div>
</div>
);
};
export default TopMenu;I guess I have one final questions ! My app is still the same, with all the router stuff, but that is useless now. What should be inside of it?
I feel like it should be empty, but if I do that, it doesn't work anymore
"use client";
import TopMenu from "./components/TopMenu";
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./home/page";
import Simulation from "./simulation/page";
import Parameter from "./parameter/page";
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<TopMenu />}>
<Route index element={<Home />} /> {/* Default Route */}
<Route path="home" element={<Home />} />
<Route path="parameter" element={<Parameter name="test" />} />
<Route path="simulation" element={<Simulation />} />
</Route>
</Routes>
</BrowserRouter>
);
}I feel like it should be empty, but if I do that, it doesn't work anymore
Double-striped Thick-knee
have you created all the other routes?
Pteromalid waspOP
If you mean the files inside the folder architecture, then yes
Double-striped Thick-knee
can you show me your folder structure,
Pteromalid waspOP
@Pteromalid wasp Click to see attachment
Double-striped Thick-knee
whats inside page.tsx
Double-striped Thick-knee
you need to put your codes inside page.tsx
// home/page.tsx
export default function page () {
return <div>This is Homepage</div>
}// parameter/page.tsx
export default function page () {
return <div>This is parameter page</div>
}these returned divs should be rendered below topMenu when visited
Pteromalid waspOP
Ah yes, I didn't put any <div> inside the return, with it it runs. I think i have one last issue, but first I want to say thank you so much for the help! it is much appreciated!
Ah actually no, everything is finally working perfectly fine, thank you so much! it make so much more sense now
@Pteromalid wasp I guess I have one final questions ! My app is still the same, with all the router stuff, but that is useless now. What should be inside of it?
typescript
"use client";
import TopMenu from "./components/TopMenu";
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./home/page";
import Simulation from "./simulation/page";
import Parameter from "./parameter/page";
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<TopMenu />}>
<Route index element={<Home />} /> {/* Default Route */}
<Route path="home" element={<Home />} />
<Route path="parameter" element={<Parameter name="test" />} />
<Route path="simulation" element={<Simulation />} />
</Route>
</Routes>
</BrowserRouter>
);
}
I feel like it should be empty, but if I do that, it doesn't work anymore
Double-striped Thick-knee
now you don't need this App component, just write your route specific codes in the corresponding page.tsx files
Pteromalid waspOP
Okay Actually i do have one last question. If I write
localhost:3000 it renders the home page, with an error, but its only visible in the page, not the terminal. And is there a way to make the home page the default page?@Pteromalid wasp Okay Actually i do have one last question. If I write `localhost:3000` it renders the home page, with an error, but its only visible in the page, not the terminal. And is there a way to make the home page the default page?
Double-striped Thick-knee
there is a file below
layout.tsx which is page.tsx. it acts as / routewrite your homepage related code inside that file
it will apear in / route, below topMenu
Pteromalid waspOP
but then, how do I redirect home to / ? In my current code, it simply takes the name of the tab and adds it to the base link. I could add an if statement, if item === home, go to "/", but maybe there's a better way?
Double-striped Thick-knee
you could use an array of object instead,
{name: "home", path: "/"}
{name: "home", path: "/"}
Pteromalid waspOP
But then this would make a tab name be "/" on the UI.
I tried writing
I tried writing
href={item === "home" ? "" : item}, but it doesn't work for the hom page 😅 I'll get there !Double-striped Thick-knee
give me 1min
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
const TopMenu = () => {
const tabName = [
{ name: "home", path: "/" },
{ name: "parameter", path: "/parameter" },
{ name: "simulation", path: "/simulation" },
];
const pathname = usePathname();
console.log(pathname);
return (
<div>
<div role="tablist" className="tabs tabs-lifted">
{tabName.map((item, index) => (
<Link role="tab" href={item} className={pathname === item.path ? "tab tab-active [--tab-bg:lightblue] [--tab-border-color:blue]" : "tab"}>
{item.charAt(0).toUpperCase() + item.slice(1)}
</Link>
))}
</div>
</div>
);
};
export default TopMenu;it should work
Pteromalid waspOP
Nice! I modified a few things, like item.name for the name of the tabs, and item.path for the href, but now it works exactly like I wantedd! Thank you
However, I still ahve that error
However, I still ahve that error
Double-striped Thick-knee
can you show your layout.tsx
Pteromalid waspOP
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";
import TopMenu from "./components/TopMenu";
const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
weight: "100 900",
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff",
variable: "--font-geist-mono",
weight: "100 900",
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" data-theme="light">
<div>
<body>
<TopMenu />
{children}
</body>
</div>
</html>
);
}I tried removing the body and the div, but it gave me an error, so I've put them back in
Double-striped Thick-knee
<html lang="en" data-theme="light">
<body>
<TopMenu />
{children}
</body>
</html>don't wrap body inside div
Pteromalid waspOP
Nice ! it works without any error now ! ILL go read about what you just said, but really, THANK YOU ! It works exactly like I wanted and it's easier than with navigate and navlink
@@ts-ignore Nextjs comes with its own router hence you don't need the `react-router-dom`
Double-striped Thick-knee
You're welcome, you can mark it as your answer
Pteromalid waspOP
Via the button on the three dot, or via a command ? (I am asking cause on the typescript server it's via a command)
Original message was deleted
Double-striped Thick-knee
right click on the message > Apps > Mark Solution
Pteromalid waspOP
thanks !