react nested routes default path blank page - javascript

How can I make the parent path render a default outlet in react router v6 nested routes?
As you can see in the example I want to make "/dashboard" path take me to "/dashboard/home" by default.
For now it's just rendering a blank screen in the Outlet.
<Route path={"dashboard"} element={<Dashboard />}>
<Route path={"home"} element={<Home />} />
<Route path={"users"} element={<Users />} />
</Route>

You can render an Index route to render some content when the path equals that of the parent route.
Example:
<Route path="dashboard" element={<Dashboard />}> // "/dashboard/*"
<Route index element={/* some content */} /> // "/dashboard"
<Route path="home" element={<Home />} /> // "/dashboard/home"
<Route path="users" element={<Users />} /> // "/dashboard/users"
</Route>
If you want a specific nested route to be a "default" then either render it again as the index route or render a redirect to it.
Examples:
<Route path="dashboard" element={<Dashboard />}>
<Route index element={<Home />} />
<Route path="home" element={<Home />} />
<Route path="users" element={<Users />} />
</Route>
or
<Route path="dashboard" element={<Dashboard />}>
<Route index element={<Navigate to="home" replace />} />
<Route path="home" element={<Home />} />
<Route path="users" element={<Users />} />
</Route>

Related

How to restrict routes in another layout react router v6

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>

React router dom 6 route structure with layouts

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>
)

How to redirect from a 3rd level nested route to the 3rd param if user manually modifies the url & hits Enter in react-router-dom-6?

I have the following basic example taken from the official react-router-dom github page and adjusted:
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="parent/:id">
<Route index element={<FirstChild />} />
<Route path=":source" element={<SecondChild />} />
</Route>
<Route path="*" element={<NoMatch />} />
</Route>
</Routes>
and the layout
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/parent/2">FirstChild</Link>
</li>
<li>
<Link to="/parent/2/editor">SecondChild</Link>
</li>
</ul>
</nav>
So when I hit SecondChild route link I navigate to myDomain/parent/2/editor.
What I would like to achieve is in case the user goes manually in the browser url and erases or modifies the last param, which in my case is editor. If the users writes editor2 and hits ENTER, how do I redirect the user to myDomain/parent/2/editor? Does anyone know if this is possible in react-router-dom#6?
Demo to play with
Edit
source is dynamic. So there are other pages with the route "/parent/:id/...". There is for instance
/parent/:id/labelbook
And I want to redirect to the correct route in case user modifies again labelbook or editor in the two different scenarios to the correct route param. In the future a third scenario maybe will be added.
In react router-dom 5 I could do that by adding ? next to the param but now this is gone. I could do
<Route path=":source?" element={<SecondChild />} />
and get the job done.
You can render a redirect at that nested level.
First, since it's unclear what exactly you want to render at the second nested level I'll provide a couple examples.
Example #1: The SecondChild component is rendered exactly on "/parent/:id/editor" and you want to redirect any other nested route to there.
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="parent/:id">
<Route index element={<FirstChild />} />
<Route path="editor" element={<SecondChild />} />
<Route path="*" element={<Navigate to="../editor" replace />} />
</Route>
<Route path="*" element={<NoMatch />} />
</Route>
</Routes>
Example #2: The SecondChild component is rendered on "/parent/:id/:source" and you explicitly want to redirect from "/parent/:id/editor2" to "/parent/:id/editor".
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="parent/:id">
<Route index element={<FirstChild />} />
<Route path=":source" element={<SecondChild />} />
<Route
path="editor2"
element={<Navigate to="../editor" replace />}
/>
</Route>
<Route path="*" element={<NoMatch />} />
</Route>
</Routes>
Example #3:
If you've a list of specific ":source" values you want to match then you should render explicit routes for each. If the SecondChild component depends on what a "source" value is then I'd suggest passing it in as a prop. Any route that isn't explicitly matched will be rendered to the "*" NoMatch route.
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="parent/:id">
<Route index element={<FirstChild />} />
<Route path="editor" element={<SecondChild source="editor" />} />
<Route path="labelbook" element={<SecondChild source="labelbook" />} />
... etc ...
<Route path="*" element={<NoMatch />} />
</Route>
</Routes>

How can I arrange my Routes on the App component

I have various routes and I also have some data from context api that I want to pass to certain routes, excluding some. So,
There is the <UserContext.Provider> that should be wrapped inside all the routes.
There is also the <Route element={<PrivateRoute />}> that sould be wrapped inside most of the routes because it should be checking the authenticated user.
And then there are components like <FruitsData> and <WeatherData> that I should only use to wrap <Route path="training" element={<Training />} /> which is inside <Route element={<PrivateRoute />}> and <UserContext.Provider>
So, my question. How can I wrap the component mentioned in no.3 the right way without having to wrap it around all the other components like I have done below?
<UserContext.Provider value={user}>
<WeatherData>
<FruitsData>
<Routes>
<Route element={<PrivateRoute />}>
<Route path="/" element={<Dashboard />} />
<Route path="/test" element={<TestPage />} />
<Route path="training" element={<Training />} />
<Route path="fruit-details/:fruitId" element={<FruitDetails />} />
<Route path="my-farm" element={<MyFarmList />} />
<Route path="add-farm" element={<AddFarm />} />
<Route path="farm-details" element={<FarmDetails />} />
<Route path="add-post" element={<AddPost />} />
<Route path="post-details/:postId" element={<PostDetails />} />
<Route path="infestation-details/:infestationId" element={<InfestationDetails />} />
<Route path="farm-details/:username/:farmId" element={<FarmDetails />} />
<Route path="farm-details/:username/:farmId/fruits" element={<FarmFruits />} />
<Route path="area" element={<Area />} />
<Route path="shop" element={<Shop />} />
<Route path="packages" element={<Packages />} />
<Route path="seedlings" element={<Seedlings />} />
<Route path="profile" element={<Profile />} />
<Route path="product-details/:seedlingId" element={<ProductDetails />} />
<Route path="pricing" element={<Pricing />} />
<Route path="community" element={<Community />} />
<Route path="complete-profile" element={<CompleteProfile />} />
</Route>
<Route path="admin/" element={<AdminPrivateRoute />}>
<Route path="home" element={<Home />} />
<Route path="farmers" element={<Farmers />} />
<Route path="farms" element={<Farms />} />
</Route>
</Routes>
</FruitsData>
</WeatherData>
</UserContext.Provider>
Thank you
I don't see any overt issue with the way all the context providers wrap the entirety of the routes, but if you are trying to limit the scope of any specific provider then the solution here is to have them render an Outlet component instead of the children prop and render them as layout routes.
Example:
const UserLayout = () => {
... logic/state/etc ...
return (
<UserContext.Provider value={user}>
<Outlet />
</UserContext.Provider>
);
};
const FruitesWeatherLayout = () => {
... logic/state/etc ...
return (
<WeatherData>
<FruitsData>
<Outlet />
</FruitsData>
</WeatherData>
);
};
...
<Routes>
<Route element={<UserLayout />}> // <-- layout route
<Route element={<PrivateRoute />}>
<Route path="/" element={<Dashboard />} />
<Route path="/test" element={<TestPage />} />
<Route element={<FruitesWeatherLayout />}> // <-- layout route
<Route path="training" element={<Training />} />
</Route>
<Route path="fruit-details/:fruitId" element={<FruitDetails />} />
<Route path="my-farm" element={<MyFarmList />} />
<Route path="add-farm" element={<AddFarm />} />
<Route path="farm-details" element={<FarmDetails />} />
<Route path="add-post" element={<AddPost />} />
<Route path="post-details/:postId" element={<PostDetails />} />
<Route path="infestation-details/:infestationId" element={<InfestationDetails />} />
<Route path="farm-details/:username/:farmId" element={<FarmDetails />} />
<Route path="farm-details/:username/:farmId/fruits" element={<FarmFruits />} />
<Route path="area" element={<Area />} />
<Route path="shop" element={<Shop />} />
<Route path="packages" element={<Packages />} />
<Route path="seedlings" element={<Seedlings />} />
<Route path="profile" element={<Profile />} />
<Route path="product-details/:seedlingId" element={<ProductDetails />} />
<Route path="pricing" element={<Pricing />} />
<Route path="community" element={<Community />} />
<Route path="complete-profile" element={<CompleteProfile />} />
</Route>
<Route path="admin/" element={<AdminPrivateRoute />}>
<Route path="home" element={<Home />} />
<Route path="farmers" element={<Farmers />} />
<Route path="farms" element={<Farms />} />
</Route>
</Route>
</Routes>

How can React-Router-Dom v6 properly distribute internal routers among components?

There is routing at the top level with internal routing, the question arose to add routing inside components such as ProductsPage, ElementsPage, etc.
<BrowserRouter>
<Routes>
<Route path='/' element={<PageLayout />}>
<Route path='marketplace'>
<Route path='products' element={<ProductsPage />} />
<Route path='constituents' element={<ElementsPage />} />
<Route path='resources' element={<ResourcesPage />} />
<Route path='shopping' element={<ShoppingPage />} />
</Route>
<Route path='resource-center'>
<Route path='planner' element={<>планирование</>} />
<Route path='resources' element={<>resources</>} />
</Route>
<Route path='*' element={<>Страница не найдена 404</>} />
</Route>
</Routes>
</BrowserRouter>
The question is how to do this in version 6. Because before version five, you could easily throw a switch into a component a la ProductsPage and specify routes in the switch
You can name all pages explicitly.
<BrowserRouter>
<Routes>
<Route path='/' element={<PageLayout />} />
<Route path='/marketplace/products' element={<ProductsPage />} />
<Route path='/marketplace/constituents' element={<ElementsPage />} />
<Route path='/marketplace/resources' element={<ResourcesPage />} />
<Route path='/marketplace/shopping' element={<ShoppingPage />} />
<Route path='/resource-center/planner' element={<планирование />} />
<Route path='/resource-centerresources' element={<resources/>} />
<Route path='*' element={<Страница не найдена 404/>} />
</Routes>
</BrowserRouter>

Categories

Resources