I am using react-router#6, and want to add a route for 404 pages, and render the page outside the main layout. This is what I have so far:
<BrowserRouter>
<Routes>
<Route path='/' element={<Layout />}>
<Route
path='/'
element={<HomePage />}
/>
<Route
path='login'
element={<LoginPage />}
/>
</Route>
<Route
path='*'
element={<PageNotFound />}
/>
</Routes>
</BrowserRouter>
The "*" route works fine, PageNotFound component is rendering outside the layout, as it should. Problem is that the any of the other routes does not show up, only the layout.
What am I missing?
From what you describe it sounds like the Layout component is missing rendering an Outlet component for the nested routes to render their content into.
Example:
import { Outlet } from 'react-router-dom';
const Layout = () => {
...
return (
<>
... common layout UI ...
<Outlet /> // <-- nested routes render out here
</>
);
};
<BrowserRouter>
<Routes>
<Route element={<Layout />}>
<Route path='/' element={<HomePage />} />
<Route path='login' element={<LoginPage />} />
</Route>
<Route path='*' element={<PageNotFound />} />
</Routes>
</BrowserRouter>
For more details you can see the following:
Layout Routes
Outlets
Related
I am having three layouts and they are Admin, App, CompanySetup. I need to restrict routes of app layout in admin layout and vice-versa. I shared my Code below.
Routes.js
<Route path='/'>
<Route path='app'>
<Route index element={<Home />}></Route>
<Route
path='search/category/:category'
element={<SearchPage />}
></Route>
<Route
path='search/category/:category/name/:name'
element={<SearchPage />}
></Route>
</Route>
<Route path='admin'>
<Route element={<AdminRouteProvider></AdminRouteProvider>}>
<Route
path='dashboard'
element={<AdminDashboard />}
></Route>
</Route>
</Route>
</Route>
AppLayout.js
<Layout className='min-vh-100 bg-white'>
<Content className='p-4'>
<Outlet />
</Content>
</Layout>
AdminLayout.js
<Layout className='min-vh-100 bg-white'>
<Sider width={240} className='bg-white border-end'>
<Sidebar />
</Sider>
<Layout>
<Header className='bg-body border-bottom'>
<HeaderNav></HeaderNav>
</Header>
<Content className='p-5 bg-body'>
<AdminRouteProvider>
<Outlet></Outlet>
</AdminRouteProvider>
</Content>
</Layout>
</Layout>
Here I am having separate layouts for '/app' and '/admin'. My issue is in admin layout '/app' is allowed. How to restrict that?
you can use useEffect/useEffectLayout to prevent from access the route or path of '/app'.
for example-
useEffect(()=>{
if(!JSON.parse(localStorage.getItem('admin')){
window.location.href="/app"
}
},[])
this is just an example may this code also change according to your need. If you still facing issue just lemme know.
From what I can tell you are not rendering any actual layout routes for either "/app" or "/admin". Import AppLayout and AdminLayout1 and render the appropriate layout routes.
import AppLayout from '../path/to/AppLayout';
import AdminLayout from '../path/to/AdminLayout';
...
<Route path="/">
<Route path="app" element={<AppLayout />}>
<Route index element={<Home />} />
<Route path="search/category/:category">
<Route index element={<SearchPage />} />
<Route path="name/:name" element={<SearchPage />} />
</Route>
</Route>
<Route path="admin" element={<AdminLayout />}>
<Route path="dashboard" element={<AdminDashboard />} />
<Route path="*" element={<Navigate to="dashboard" replace />} />
</Route>
</Route>
Below code is the entry point
<React.StrictMode>
<AppProvider>
<BrowserRouter>
<Routes>
<Route path='/admin/*' element={<Admin />} />
<Route path='*' element={<App />} />
</Routes>
</BrowserRouter>
</AppProvider>
</React.StrictMode>
I have Child routes under App.js and Admin.js, but routes under Admin is not routing as expected at the same time App.js routes are working accordingly.
Code for Admin.js is below
<div>
<ASideMenuNav />
<Routes>
<Route path='/admin/product' element={<AProductsInfo />} />
<Route path='/admin/offers' element={<AProductOffers />} />
</Routes>
</div>
Output is as shown below
enter image description here
Problem I am facing here is that when I click on any navigation menu its URL is changing but the content of the particular React component is not showing up.
Someone please tell me what am I missing. Is there something wrong with coding logic?
Descendent routes in the Routes component will have their paths built relative to the parent route. If the parent route path is "/admin/*" then the current paths are "/admin/admin/product" and "/admin/admin/offers". The solution is to remove the "/admin" path prefix on the descendent routes.
<div>
<ASideMenuNav />
<Routes>
<Route path="/product" element={<AProductsInfo />} />
<Route path="/offers" element={<AProductOffers />} />
</Routes>
</div>
Alternatively the Admin component could render an Outlet component and the routes could be converted to nested routes in the App.
<div>
<ASideMenuNav />
<Outlet />
</div>
<React.StrictMode>
<AppProvider>
<BrowserRouter>
<Routes>
<Route path='/admin' element={<Admin />}>
<Route path="product" element={<AProductsInfo />} />
<Route path="offers" element={<AProductOffers />} />
</Route>
<Route path='*' element={<App />}/>
</Routes>
</BrowserRouter>
</AppProvider>
</React.StrictMode>
I have this page structure
login (Root page)
forget password
dashboard (Wrapper layout needed)
orders (Wrapper layout needed)
The orders page and Dashboard needed the wrapper layout.
Right now I have this code
const routes = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<RootLayout />}>
<Route path="orders" element={<Orders />} />
<Route path="dashboard" element={<Dashboard />} />
</Route>
)
);
And this is root layout
export default function RootLayout() {
return (
<div>
<header>
<h1>This top header</h1>
</header>
<main>
<Outlet/>
</main>
</div>
)
}
I am unsure how I can add Login page to the root path and Forget password page to the "/forget-password" path. RootLayout should not wrap in those two pages as well.
I have tried this approach even though it is adding a extra "/app" part. But this also not working as intended
createRoutesFromElements(
<Route path="/" element={<Login />}>
<Route path="app" element={<RootLayout />}>
<Route path="orders" element={<Orders />} />
<Route path="dashboard" element={<Dashboard />} />
</Route>
</Route>
)
How can I achieve this with react-router-dom#6?
createRoutesFromElements expects a single React node. Render a single "outer" route on "/" with no element which will render an Outlet by default. "RootLayout" is a layout route and doesn't need to participate in the route path matching, omit the path="app" prop.
createRoutesFromElements(
<Route path="/">
<Route index element={<Login />} /> // <-- "/"
<Route
path="forgot-password // <-- "/forgot-password"
element={<ForgotPassword />}
/>
<Route element={<RootLayout />}>
<Route
path="orders" // <-- "/orders"
element={<Orders />}
/>
<Route
path="dashboard" // <-- "/dashboard"
element={<Dashboard />}
/>
</Route>
</Route>
)
As I mentioned I have MUI Theme Provider with Layout which includes Dashboard, Order screens ...
When user hits '/' endpoint it should return Login Screen but Layout keeps showing itself.
-App.js
<ThemeProvider theme={theme}>
<Router>
<Layout>
<Switch>
<Route exact path="/">
<Login />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
<Route path="/orders">
<Orders />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/employees">
<Employee />
</Route>
</Switch>
</Layout>
</Router>
</ThemeProvider>
);
-Layout.js
...AppBar,Sidebar etc
<div style={{width:'100%'}}>
<div className={classes.toolbar}></div>
{children}
</div>
As-is, the code is unconditionally rendering a Layout component outside the Switch, so it's rendered regardless of the currently matched route.
If you want the Layout component to only render on certain routes, conditionally render it with those routes.
Example, render the Login component on exactly the "/" path, everything else into a route rendering the Layout and another Switch.
<ThemeProvider theme={theme}>
<Router>
<Switch>
<Route exact path="/">
<Login />
</Route>
<Route path="/">
<Layout>
<Switch>
<Route path="/dashboard">
<Dashboard />
</Route>
<Route path="/orders">
<Orders />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/employees">
<Employee />
</Route>
</Switch>
</Layout>
</Route>
</Switch>
</Router>
</ThemeProvider>
In my code, I want Header & Footer components to be rendered in all routes except '/login'so how to do that? How to hide component on a specific route?
const AppRouter = () => {
return (
<BrowserRouter>
<div>
<Header />
<Switch>
<Route path="/login" component={Login} /> {/* I wanna render this route without Header & Footer */}
<Route path="/" component={Home} exact />
<Route path="/product" component={ProductOverview} />
<Route path="/profile" component={Profile} />
<Route component={NotFound} />
</Switch>
<Footer />
</div>
</BrowserRouter>
);
};