I am trying to build a website using ReactJS. Currently, I have a home page and a navbar. None of these components are displayed when trying to view them inside the browser. I guess the problem sits inside of my router, but i can't really put my finger on it.
These are the two components/pages I want to display:
Home.tsx
import Background from "../components/Background";
export default function Home() {
return (
<div>
<Background />
<h1>Testing text</h1>
</div>
);
}
Navbar.tsx
import Link, { LinkProps } from "../components/Link";
const navElements: LinkProps[] = [
{
label: "Configure",
to: "/Configure",
},
{
label: "Archive",
to: "/Archive",
},
{
label: "About",
to: "/About",
},
{
label: "Contact",
to: "/Contact",
},
];
export default function Navbar() {
return (
<div className="flex font-serif space-x-4">
{navElements.map((navElement) => (
<Link {...navElement} key={navElement.label} />
))}
</div>
);
}
These components are brought together in the Routing.tsx:
import { Route, Routes, BrowserRouter, Outlet } from "react-router-dom";
import Home from "../pages/Home";
import Navbar from "../layout/Navbar";
export default function Routing() {
return (
<BrowserRouter>
<Routes>
<Route
element={
<>
<Navbar />
<Outlet />
</>
}
/>
<Route path="home">
<Route index element={<Home />}></Route>
</Route>
</Routes>
</BrowserRouter>
);
}
The router is finally put into App.tsx
According to the docs, index routes are displayed on parent element's Outlet component.
In your case parent route doesn't have any element. change into this.
<Route path="home" element={<Home />}>
//add any index route with element if you want
</Route>
After some trial and error (including #Arjun's answer) it worked with the following line of code (part of Routing.tsx):
<BrowserRouter>
<Routes>
<Route
element={
<>
<Navbar />
<Outlet />
</>
}
>
<Route index element={<Home />} />
</Route>
</Routes>
</BrowserRouter>
);
}
Related
Why is rendering the parent component and the child trying to enter the child component
"react-router-dom": "^6.0.1",
when I enter on the route:
http://localhost:3000/dashboard- the view work
http://localhost:3000/dashboard/employee - rendering dashboard and employee view (both views)
http://localhost:3000/dashboard/accounting - rendering dashboard and accounting view (both views)
Documentation:
https://reactrouter.com/docs/en/v6/getting-started/tutorial#nested-routes
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
App.js
import AppRouter from "./routers/AppRouter";
function App() {
return (
<>
<AppRouter />
</>
);
}
export default App;
AppRouter.js
import { Route, Routes } from "react-router-dom";
import Navbar from "../components/template/Navbar";
import AccountingHomeView from "../components/views/accounting/AccountingHomeView";
import DashboardHomeView from "../components/views/dashboard/DashboardHomeView";
import EmployeeHomeView from "../components/views/employee/EmployeeHomeView";
import HomeView from "../components/views/public/HomeView";
import LoginView from "../components/views/public/LoginView";
const AppRouter = () => {
return (
<div>
<Navbar />
<Routes>
<Route path="/" element={<HomeView />} />
<Route path="dashboard" element={<DashboardHomeView />}>
<Route path="employee" element={<EmployeeHomeView />} />
<Route path="accounting" element={<AccountingHomeView />} />
</Route>
<Route path="/login" element={<LoginView />} />
</Routes>
</div>
);
};
export default AppRouter;
DashboardHomeView.js (with outlet)
import { Outlet } from "react-router-dom";
const DashboardHomeView = function () {
return (
<>
<h1>DashboardHomeView</h1>
<Outlet />
</>
);
};
export default DashboardHomeView;
component children Accounting
import React from "react";
const AccountingHomeView = function () {
return (
<div>
<h1> Accountin</h1>
</div>
);
};
export default AccountingHomeView;
I also initially found this a bit confusing, but with nested routes the "parent" route is considered more of a "layout" component in that it is always rendered when its path matches, and renders all its children routes into its outlet.
const AppRouter = () => {
return (
<div>
<Navbar />
<Routes>
<Route path="/" element={<HomeView />} />
<Route
path="dashboard"
element={<DashboardHomeView />} // <-- always matched/rendered at "/dashboard*"
>
<Route
path="employee"
element={<EmployeeHomeView />} // <-- conditionally matched/rendered
/>
<Route
path="accounting"
element={<AccountingHomeView />} // <-- conditionally matched/rendered
/>
</Route>
<Route path="/login" element={<LoginView />} />
</Routes>
</div>
);
};
const DashboardHomeView = function () {
return (
<>
<h1>DashboardHomeView</h1> // <-- always matched/rendered at "/dashboard*"
<Outlet /> // <-- conditionally matched/rendered children
</>
);
};
Nested-Routes
You may have noticed when clicking the links that the layout in App
disappears. Repeating shared layouts is a pain in the neck. We've
learned that most UI is a series of nested layouts that almost always
map to segments of the URL so this idea is baked right in to React
Router.
I believe what you are expecting is what is called an Index Route. It is what would be rendered on a "/dashboard" route when it isn't a layout/wrapper container.
Notice it has the index prop instead of a path. That's because the
index route shares the path of the parent. That's the whole point--it
doesn't have a path.
Maybe you're still scratching your head. There are a few ways we try
to answer the question "what is an index route?". Hopefully one of
these sticks for you:
Index routes render in the parent routes outlet at the parent route's path.
Index routes match when a parent route matches but none of the other children match.
Index routes are the default child route for a parent route.
Index routes render when the user hasn't clicked one of the items in a navigation list yet.
const AppRouter = () => {
return (
<div>
<Navbar />
<Routes>
<Route path="/" element={<HomeView />} />
<Route path="dashboard" element={<DashboardLayout />}>
<Route path="employee" element={<EmployeeHomeView />} />
<Route path="accounting" element={<AccountingHomeView />} />
<Route index element={<DashboardHomeView />} />
</Route>
<Route path="/login" element={<LoginView />} />
</Routes>
</div>
);
};
const DashboardLayout = function () {
return (
<div /* with any layout styling */>
.... other common layout content
<Outlet />
.... more possible common page content
</div>
);
};
const DashboardHomeView = function () {
return (
<>
<h1>DashboardHomeView</h1>
.... dashboard specific content
</>
);
};
How about using the exact prop for the parent Route. Like <Route exact path="dashboard" element={<DashboardHomeView />}>. This may solve the issue.
So I have a route like in the documentation: <Route path="*"><Redirect to={'/'}/></Route>.
To make sure that all routes lead to '/' if the route doesnt exists.
All my routes work with a <Link> tag but not when I type them in the URL bar.
How can this be? I cant find information about this online.
index file:
return(
<Fragment>
<BrowserRouter basename={`/`}>
<Switch>
<App>
<TransitionGroup>
{routes.map(({ path, Component }) => (
<Route key={path} exact path={`${process.env.PUBLIC_URL}${path}`}>
{({ match }) => (
<CSSTransition in={match != null} timeout={100} classNames={anim} unmountOnExit>
<div><Component/></div>
</CSSTransition>
)}
</Route>
))}
<Route exact path="*"><Redirect to={'/'}/></Route>
</TransitionGroup>
</App>
</Switch>
</BrowserRouter>
</Fragment>
)
Route file:
export const routes = [
{
path:`/`,
Component:Home
},
{
path:`/login`,
Component:Login
},
{
path:`/signup`,
Component:Signup
},
{
path:`/event/:name`,
Component:Event
},
{
path:`/create-event`,
Component:CreateEvent
},
]
Link tag:
<Link to={"/event/" + events[i].name} className="text-dark">
From the react-router documentation,
All children of a <Switch> should be <Route> or <Redirect> elements. Only the first child to match the current location will be rendered.
I can see <Route> is not a direct or first child to <Switch>
Use Switch from react-router to renders the first child that matches the location. And be sure to keep, all the known routes before * to avoid redirection to the / path. Following is an example, for your case.
import React from "react";
import {
BrowserRouter as Router,
Route,
Switch,
Redirect,
} from "react-router-dom";
class App extends React.Component {
render() {
return (
<Router>
<Switch>
<Route exact path="/" component={() => <div>{"MAIN"}</div>} />
<Route
exact
path="/event/:name"
component={() => <div>{"SELECTED EVENT"}</div>}
/>
<Route exact path="*" component={() => <Redirect to={"/"} />} />
</Switch>
</Router>
);
}
}
export default App;
Hope this would solve your issue.
I hoe you are doing well :)
when I click on a link from the navbar, the home link is always active. I tried to add excat to the home route but nothing changed?
if someone can help me please that would be great.
thank you in advance
thank you for your time
import { NavLink } from "react-router-dom";
import { links } from "../utils/constants";
import styled from "styled-components";
const NavMenu = () => {
return (
<Nav>
<ul>
{links.map((link) => {
const { id, url, text } = link;
return (
<li key={id}>
<NavLink to={url}>{text}</NavLink>
</li>
);
})}
</ul>
</Nav>
);
};
const Nav = styled.nav`
////////
.active {
color: var(--white);
}
}
`;
export default NavMenu;
APP.js
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { NavMenu } from "./components";
import { Home, About, Projects, Contact, Error } from "./pages";
const App = () => {
return (
<Router>
<NavMenu />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/about">
<About />
</Route>
<Route exact path="/projects">
<Projects />
</Route>
<Route exact path="/contact">
<Contact />
</Route>
<Route path="*">
<Error />
</Route>
</Switch>
</Router>
);
};
export default App;
I think you are not using Route Component properly. You should try in this way.
Pass the path and component in the Route instead of wrapping it inside in Route component.
import { HomePage, UserPage } from "./pages";
const routes = [
{
path: '/home',
component: HomePage,
},
{
path: '/user',
component: UserPage,
}]
<Switch>
{routes.map(({ path, component }, index) => (
<Route key={String(index)} exact path={path} component={component} />
))}
</Switch>
I put all routes as children of Material UI Drawer and use as props. Since the login page cant have the Drawer, how can I structure the login route so that it doesn't include the drawer?
What I'm trying now joins everything together
function App(props) {
const { history } = props;
return (
<BrowserRouter>
<Route path="/" exact component={Login} />
<Drawer history={history}>
<Switch>
<Route path="/kids" component={Listing} />
<Route path="/register" component={Register} />
</Switch>
</Drawer>
</BrowserRouter>
);
}
export default App;
You can create a wrapper of MUI's Drawer that conditionally renders the Drawer based on the current route. For example:
import { useLocation } from "react-router-dom";
function isAuthRoute(pathname: string) {
return pathname === "/" || pathname === "/register";
}
function MyDrawer() {
const location = useLocation();
if (isAuthRoute(location.pathname)) {
return null;
}
return (
<Drawer>
{...}
</Drawer>
);
}
Then include MyDrawer in every page. You can create a Layout component to streamline that process:
function Layout({ children }) {
return (
<>
{children}
<MyDrawer />
</>
)
}
function LoginPage() {
return (
<Layout>
<LoginContent />
</Layout>
)
}
function ListingPage() {
return (
<Layout>
<ListingContent />
</Layout>
)
}
Finally in your App, declare the Routes as normal, the Drawer inside will know when to render correctly.
export default function App() {
return (
<BrowserRouter>
<Switch>
<Route path="/" exact component={LoginPage} />
<Route path="/kids" component={ListingPage} />
<Route path="/register" component={RegisterPage} />
</Switch>
</BrowserRouter>
);
}
I am trying to use nested routes to render different components. When I click my links, URL does update but the components are not rendering. Prior to this I was using imported components, but since that wasn't working, I stripped it down to this block of code and it's still just showing a blank component and no errors.
import React from 'react';
import { Route, Switch, Link, useRouteMatch } from 'react-router-dom';
function InfluencerComponent() {
let { path, url } = useRouteMatch();
const navLinks = (
<div>
<Link to={`${url}/select-trade`}>Select trade</Link>
<Link to={`${url}/add-skills`} className="ml-2">
Add skills
</Link>
</div>
);
return (
<div className="row mt-3">
<Switch>
<Route exact path={path}>
{navLinks}
</Route>
<Route path={`${path}/select-trade`}>
{navLinks}
<Test />
</Route>
<Route path={`${path}/add-skills`}>
{navLinks}
<TestTwo />
</Route>
</Switch>
</div>
);
}
function Test() {
return 'Test Component';
}
function TestTwo() {
return 'Another Test Component';
}
export default InfluencerComponent;
Components are not rendering because you should use component prop instead of children.
Example:
return (
<div className="row mt-3">
<Switch>
// ...
<Route path={`${path}/add-skills`} component={<>{navLinks}<TestTwo /></>} />
</Switch>
</div>
);
More info about <Route /> props:
https://reacttraining.com/react-router/web/api/Route/component