Which way to declare nested routes in React-Router-Dom - javascript

I'm working with reactJs and trying to create some nested routes.
Below you can see the routing parts of my files :
main.js :
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('page')
);
App.js :
class App extends Component {
render() {
return (
<div>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
<Route path="/signup" component={SignUp} />
<Route path="/contact" component={Contact} />
<ProtectedRoute path="/user/profile" component={Profile} />
<Route component={NotFound} />
</Switch>
<Footer />
</div>
);
}
}
Don't ask me why, but I want to create the following url's :
/signup : SignUp form
/signup/person : SignUp form part 2
/signup/person/:id : SignUp user id informations
I added this in my App.js file and It's works :
<Route exact path="/signup" component={SignUp} />
<Route exact path="/signup/person" component={SignUpPerson} />
<Route path="/signup/person/:id" component={SignUpId} />
But I want to know if it's a good way to create nested routes or it's better to separate the route like this post : https://stackoverflow.com/a/43846223/4023379
Or maybe an other way ?
Thanks

use nested routes if Pages have common logic/components like Header, Footer.
use separate routes if Page doesn't share similar logic. just because of url start with /singup not necessary mean you have to nested your components

Related

React-Router cannot access to the below routes

I am making a simple login app. I have public and private routes. And I also have a variable route that can access to both private and public users. So far I created routes from public and private users. But that variable route for both users is not accessible. How can I solve this issue. I am using router-dom v5
<Route path={"/forgot-password"}>
<ForgetPwd />
</Route>
<Route path={"/verifyEmail"}>
<EmailVarification />
</Route>
<Route path={"/recover-password"}>
<Recoverpassword />
</Route>
<PostProvider>
<Layout>
<PrivateRoutes path="/dashboard">
<Dashboard />
</PrivateRoutes>
</Layout>
</PostProvider>
<Route path="/:id?">
<Publicpage />
</Route>
I Think above question is not very clear. so I will explain my question more
<BrowserRouter>
<Switch>
<Route path={"/home"}>
<Home />
</Route>
<Route path={"/"}>
{/* I need to add some logic to Protect these routes */}
<Switch>
<Route path={"/about"}>
<About />
</Route>
</Switch>
</Route>
{/* This below route cannot access */}
<Route path={"/:id"}>
<PublicPage />
</Route>
</Switch>
</BrowserRouter>
I want to create simple react-router but I need public page to display data according to entered code name. And also I need to have some protected routes also. So I created some protected routes and my variable public route placed end of the routes So it will not clash with static routes. My question is after that protected route, react-router is not looking outside that scope. Below routes are not rendered
Issue
I think I'm reading between the lines here and guessing/assuming that you are rendering these routes within a Switch component. If this is the case then the issue is that the only valid children components of the Switch are the Route and Redirect components. When the PostProvider component is reached, route matching ceases and the PostProvider component is returned/rendered.
Solution
Refactor/restructure the components to render the custom PrivatesRoutes component at the Switch component level so routes can continued to be matched and rendered. Move the PostProvider component inside the route.
Example:
<Switch>
... other more specific routes ...
<Route path="/forgot-password">
<ForgetPwd />
</Route>
<Route path="/verifyEmail">
<EmailVarification />
</Route>
<Route path="/recover-password">
<Recoverpassword />
</Route>
<PrivateRoutes path="/dashboard">
<PostProvider> // <-- PostProvider moved into route
<Layout> // <-- Layout moved into route
<Dashboard />
</Layout>
</PostProvider>
</PrivateRoutes>
<Route path="/:id?">
<Publicpage />
</Route>
... other routes ...
</Switch>
Update
<BrowserRouter>
<Switch>
<Route path={"/home"}>
<Home />
</Route>
<Route path={"/"}>
{/* I need to add some logic to Protect these routes */}
<Switch>
<Route path={"/about"}>
<About />
</Route>
</Switch>
</Route>
{/* This below route cannot access */}
<Route path={"/:id"}>
<PublicPage />
</Route>
</Switch>
</BrowserRouter>
Within the Switch component path order and specificity matters. The less specific path="/" route is ordered before the "/:id" path, so "/" will always be matched and rendered and any routes listed after will effectively be unreachable.
Within Switch components you should order the routes by inverse order of path specificity. "/home" is more specific than "/:id" is more specific than "/", and this should be the order for these three routes.
<BrowserRouter>
<Switch>
<Route path="/home">
<Home />
</Route>
<Route path="/:id}>
<PublicPage />
</Route>
<Route path="/">
<Switch>
<Route path="/about">
<About />
</Route>
</Switch>
</Route>
</Switch>
</BrowserRouter>
The same holds true when using custom route components.
Example PrivateRoute component:
const PrivateRoute = props => {
// auth logic
return isAuth ? <Route {...props} /> : <Redirect to="/login" />;
};
...
<BrowserRouter>
<Switch>
<Route path="/home">
<Home />
</Route>
<PrivateRoute path="/about">
<About />
</PrivateRoute>
<Route path="/:id}>
<PublicPage />
</Route>
</Switch>
</BrowserRouter>

Converting from React-Router-dom v5 to v6 page contents not showing

I am having issues converting my code from meeting React-Router-Dom v5 requirements to V6 requirements. For some reason my webpage contents are not loading in the browser. Any help please? Ive tried doing the research and implementing different solutions but I havnt been able to fix the issue.
Here is my App.js
https://i.stack.imgur.com/USV67.png
Here is my index.js
https://i.stack.imgur.com/KG96P.png
Move TopBar out of the Routes component and move the Single component onto the route's element prop. The only valid children of the Routes component are the React.Fragment and Route components, and the only valid children of the Route component are other Route components.
Example:
function App() {
const user = false;
return (
<>
<TopBar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/register" element={<Register />} />
<Route path="/login" element={<Login />} />
<Route path="/write" element={<Write />} />
<Route path="/settings" element={<Settings />} />
<Route path="/post/:postId" element={<Single />} />
</Routes>
</>
);
}

How to create a dynamic route in react with react router

Please am finding it difficult to create a route in react router
I want to create a route like this <Route path="/:storeId" component={StorePage} />
But I also have a route like this /stores
Any time I go to the /:storeId page it loads the /users page
Am just confuse
Here is the code
<Switch>
<ScrollToTop>
<MainLayout>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/stores">
<Stores />
</Route>
<Route exact path="/:storeId">
<StorePage />
</Route>
</MainLayout>
</ScrollToTop>
</Switch>
Any help please.
You should do something like this
<Switch>
<Route exact path="/users">
<Users/>
</Route>
<Route path="/users/:id">
<UserById/>
</Route>
</Switch>

React Router - How to IndexRedirect to dynamic route

I have a situation in my React app to look like something as follows using react-router. I want the index of the users/:userId endpoint to redirect to another endpoint that includes a :userId params. What is a good way to do this? Right now the user from currentUser will return null because the code is only executed once in the beginning when the App is loaded the user is not yet authenticated. I'm guessing I will need to force react-router to reload the history and certain variables, or change the order of when I do authentication?
routes.js
{ /* Routes requiring login */ }
<Route onEnter={requireLogin}>
<Route path="users" component={Users}>
<Route path=":userId" component={User}>
<IndexRedirect to={`/users/${currentUser().id}/profile`} />
<Route path="profile" component={UserProfile} />
<Route path="settings" component={UserSettings} />
<Route path="activity" component={UserActivity} />
</Route>
</Route>
</Route>
If I understand it correctly and you want to redirect from /users/1 to /users/1/profile and /users/2 to /users/2/profile, you can simply replace ${currentUser().id} with :userId.
So your code would looks like this:
<Route onEnter={requireLogin}>
<Route path="users" component={Users}>
<Route path=":userId" component={User}>
<IndexRedirect to="profile" />
<Route path="profile" component={UserProfile} />
<Route path="settings" component={UserSettings} />
<Route path="activity" component={UserActivity} />
</Route>
</Route>
</Route>
Because the redirect is in the context of the route :userId: you can simply define your target route relative.

How to set the DefaultRoute to another Route in React Router

I have the following:
<Route name="app" path="/" handler={App}>
<Route name="dashboards" path="dashboards" handler={Dashboard}>
<Route name="exploreDashboard" path="exploreDashboard" handler={ExploreDashboard} />
<Route name="searchDashboard" path="searchDashboard" handler={SearchDashboard} />
<DefaultRoute handler={DashboardExplain} />
</Route>
<DefaultRoute handler={SearchDashboard} />
</Route>
When using the DefaultRoute, SearchDashboard renders incorrectly since any *Dashboard needs to rendered within Dashboard.
I would like for my DefaultRoute within the "app" Route to point to the Route "searchDashboard". Is this something that I can do with React Router, or should I use normal Javascript (for a page redirect) for this?
Basically, if the user goes to the home page I want to send them instead to the search dashboard. So I guess I'm looking for a React Router feature equivalent to window.location.replace("mygreathostname.com/#/dashboards/searchDashboard");
You can use Redirect instead of DefaultRoute
<Redirect from="/" to="searchDashboard" />
Update 2019-08-09 to avoid problem with refresh use this instead, thanks to Ogglas
<Redirect exact from="/" to="searchDashboard" />
Source:
https://stackoverflow.com/a/43958016/3850405
Update for version 6.4.5 to 6.8.1 <:
Use replace={true} for Navigate component.
<Routes>
<Route path="/" element={<Navigate to="/searchDashboard" replace={true} />}>
<Route path="searchDashboard" element={<SearchDashboard/>} />
<Route
path="*"
element={<Navigate to="/" replace={true} />}
/>
</Route>
</Routes>
https://reactrouter.com/en/6.4.5/components/navigate
https://reactrouter.com/en/6.8.1/components/navigate
Thanks to #vicky for pointing this out in comments.
Update:
For v6 you can do it like this with Navigate. You can use a "No Match" Route to handle "no match" cases.
<Routes>
<Route path="/" element={<Navigate to="/searchDashboard" />}>
<Route path="searchDashboard" element={<SearchDashboard/>} />
<Route
path="*"
element={<Navigate to="/" />}
/>
</Route>
</Routes>
https://reactrouter.com/docs/en/v6/getting-started/tutorial#adding-a-no-match-route
https://stackoverflow.com/a/69872699/3850405
Original:
The problem with using <Redirect from="/" to="searchDashboard" /> is if you have a different URL, say /indexDashboard and the user hits refresh or gets a URL sent to them, the user will be redirected to /searchDashboard anyway.
If you wan't users to be able to refresh the site or send URLs use this:
<Route exact path="/" render={() => (
<Redirect to="/searchDashboard"/>
)}/>
Use this if searchDashboard is behind login:
<Route exact path="/" render={() => (
loggedIn ? (
<Redirect to="/searchDashboard"/>
) : (
<Redirect to="/login"/>
)
)}/>
I was incorrectly trying to create a default path with:
<IndexRoute component={DefaultComponent} />
<Route path="/default-path" component={DefaultComponent} />
But this creates two different paths that render the same component. Not only is this pointless, but it can cause glitches in your UI, i.e., when you are styling <Link/> elements based on this.history.isActive().
The right way to create a default route (that is not the index route) is to use <IndexRedirect/>:
<IndexRedirect to="/default-path" />
<Route path="/default-path" component={DefaultComponent} />
This is based on react-router 1.0.0. See https://github.com/rackt/react-router/blob/master/modules/IndexRedirect.js.
UPDATE : 2020
Instead of using Redirect, Simply add multiple route in the path
Example:
<Route exact path={["/","/defaultPath"]} component={searchDashboard} />
Jonathan's answer didn't seem to work for me. I'm using React v0.14.0 and React Router v1.0.0-rc3. This did:
<IndexRoute component={Home}/>.
So in Matthew's Case, I believe he'd want:
<IndexRoute component={SearchDashboard}/>.
Source: https://github.com/rackt/react-router/blob/master/docs/guides/advanced/ComponentLifecycle.md
Since V6 was released recently, the accepted answer won't work since Redirect no more exists in V6. Consider using Navigate.
<Route path="/" element={<Navigate to="/searchDashboard" />} />
Ref:- V6 docs
import { Route, Redirect } from "react-router-dom";
class App extends Component {
render() {
return (
<div>
<Route path='/'>
<Redirect to="/something" />
</Route>
//rest of code here
this will make it so that when you load up the server on local host it will re direct you to /something
May 2022
Import Navigate
import { Routes, Route, Navigate } from 'react-router-dom';
Add
<Route path="/" element={<Navigate replace to="/home" />} />
For example:
import React from 'react';
import { Routes, Route, Navigate } from 'react-router-dom';
import Home from './pages/Home';
import Login from './pages/Login';
const Main = () => {
return (
<Routes>
<Route path="/" element={<Navigate replace to="/home" />} />
<Route path='home' element={<Home />}></Route>
<Route path='login' element={<Login />}></Route>
</Routes>
);
}
export default Main;
Done!
I ran into a similar issue; I wanted a default route handler if none of the route handler matched.
My solutions is to use a wildcard as the path value. ie
Also make sure it is the last entry in your routes definition.
<Route path="/" component={App} >
<IndexRoute component={HomePage} />
<Route path="about" component={AboutPage} />
<Route path="home" component={HomePage} />
<Route path="*" component={HomePage} />
</Route>
For those coming into 2017, this is the new solution with IndexRedirect:
<Route path="/" component={App}>
<IndexRedirect to="/welcome" />
<Route path="welcome" component={Welcome} />
<Route path="about" component={About} />
</Route>
<Route name="app" path="/" handler={App}>
<Route name="dashboards" path="dashboards" handler={Dashboard}>
<Route name="exploreDashboard" path="exploreDashboard" handler={ExploreDashboard} />
<Route name="searchDashboard" path="searchDashboard" handler={SearchDashboard} />
<DefaultRoute handler={DashboardExplain} />
</Route>
<Redirect from="/*" to="/" />
</Route>
The preferred method is to use the react router IndexRoutes component
You use it like this (taken from the react router docs linked above):
<Route path="/" component={App}>
<IndexRedirect to="/welcome" />
<Route path="welcome" component={Welcome} />
<Route path="about" component={About} />
</Route>
Firstly u need to install:
npm install react-router-dom;
Then u need to use your App.js (in your case it can be different) and do the modification below.
In this case I selected the Redirect to get proper rendering process.
import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom";
<Router>
<Suspense fallback={<Loading />}>
<Switch>
<Route exact path="/">
<Redirect to="/Home" component={Routes.HomePage}/>
</Route>
<Route exact path="/Biz" component={Routes.Biz} />
</Switch>
</Suspense>
</Router>
U successfully do the modification above u can see the redirect URL is on your browser path and rendering process also working properly according to their component.
Some time ago, we had an opportunity to use the component named "DefaultRoute" in the react routing.
Now, its depreciated method, and it’s not so popular to use it, you can create the custom route named default or whatever, but still, it’s not how we do it in modern React.js development.
It’s just because using the "DefaultRoute" route, we can cause some rendering problems, and its the thing that we definitely would like to avoid.
Here is how I do it-
<Router>
<div className="App">
<Navbar />
<TabBar />
<div className="content">
<Route exact path={["/default", "/"]}> //Imp
<DefStuff />
</Route>
<Route exact path="/otherpage">
<Otherstuff />
</Route>
<Redirect to="/defult" /> //Imp
</div>
</div>
</Router>
Use:
<Route path="/" element={<Navigate replace to="/expenses" />} />
In context:
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
<BrowserRouter>
<Routes>
<Route element={<App />}>
<Route path="/expenses" element={<Expenses />} />
<Route path="/invoices" element={<Invoices />} />
</Route>
<Route path="/" element={<Navigate replace to="/expenses" />} />
</Routes>
</BrowserRouter>
You use it like this to redirect on a particular URL and render component after redirecting from old-router to new-router.
<Route path="/old-router">
<Redirect exact to="/new-router"/>
<Route path="/new-router" component={NewRouterType}/>
</Route>

Categories