IndexRoute sub-routes - javascript

I have a web site with few ordinary pages and a page with Google Map. When map marker is clicked a panel with marker details is displayed next to the map. This detail has own URL so that users can link to it:
<Route path="/" component={App}>
<IndexRoute component={Welcome} />
<Route path="map" component={Map}>
{/* Detail is a child component of Map,
it only adds detail panel markup to Map. */}
<Route path="detail/:id" component={Detail} />
</Route>
<Route path="about" component={About} />
</Route>
This works fine. But let's get rid of Welcome page and display Map right on the web root so that:
/ renders App > Map components
/detail/:id renders App > Map > Detail components
/about renders App > About components
<Route path="/" component={App}>
{/* Map has to be IndexRoute so that it is displayed at root URL. */}
<IndexRoute component={Map}>
<Route path="detail/:id" component={Detail} />
</IndexRoute>
<Route path="about" component={About} />
</Route>
But this doesn't work because IndexRoute can't have subroutes.
This is the best solution I have found:
<Route path="/" component={App}>
<Route component={Map}>
<IndexRoute component={EmptyComponent} />
<Route path="detail/:id" compoent={Detail} />
</Route>
<Route path="about" component={About} />
</Route>
But I don't like the empty component.
Am I missing something? Am I doing something unusual? Why it is not possible to do it the first more intuitive way?

Move the / path
<Route component={App}>
<Route path="/" component={Map}>
<Route path="detail/:id" component={Detail}/>
</Route>
<Route path="/about"/>
</Route>

Your solution looks largely fine to me – the only caveat is that you don't need to specify the component in that case; just do <IndexRoute />.
By design, index routes terminate matching, but it's easy to insert trivial routes.

Maybe I am wrong but it seems as if your tried to set another route in:
<IndexRoute component={Map}>
<Route path="detail/:id" component={Detail} />
</IndexRoute>
So your basic structure is something like:
<IndexRoute>
<Route> </Route>
</IndexRoute>
According to your error it is not allowed that there is a <Route> inside of your <IndexRoute>... At the beginning you did not do that mistake because you closed the <IndexRoute> before you opened the next <Route>-Tag.
So if you want your code to work again you should not open another <Route> inside of your <IndexRoute>. You managed to fix this by adding an Dummy-IndexRoute. So if you want to set your Map component as IndexRoute you will have to change your HTML structure so that there is no Detail component inside of your map component because then you will have the same problem again that you got a <Route> inside your <IndexRoute>

Related

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 nested routes with exact path

Please help. I'm trying to make nested routes but here is a problem: if I use exact path, I can't have nested routes.
For example, I want to have one route that is nested and one individual. I have to use exact if I want to have an individual one. How can I have both?
<Route exact path="/projects" component={Projects} />
<Route path="/projects/individual" component={ProjectsList} />
<Route path="/projects/nested" component={ProjectsList} />
Here is codesandbox.
You are right, with an exact attribute you loose the flexibility to use nested routes. The solution here is to make use of Switch and order your routes such that the prefix paths are at the end
<Switch>
<Route path="/projects" component={Projects} />
<Route path="/" component={Home} />
</Switch>
and inside Projects you can write the nested paths
<Route path="/projects/individual" component={ProjectsList} />
<Route path="/projects/nested" component={ProjectsList} />
Update:
If however on ProjectsList component i.e paths "/projects/individual" and "/projects/nested" you do not want to render Projects component you would use them like
<Switch>
<Route path="/projects/individual" component={ProjectsList} />
<Route path="/projects/nested" component={ProjectsList} />
<Route path="/projects" component={Projects} />
<Route path="/" component={Home} />
</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 mimic DefaultRoute in React Router 1.0

So, switching to the latest React Router (1.0.0RC3). I have run into a piece of old functionality that I can't find how to replicate with the new 1.0 API.
In my Router, I always render a top-level App component, then a second-level Layout component, then a Page component. In the old React Router, I didn't have to put a path property on a Route, so I could "group" certain routes to have a parent component without adding another level to my url.
Below, you'll see that when hitting the / route, I try to load App, DefaultLayout, and Home. However, it won't render DefaultLayout without an explicit path property. So if I put path="app" on my default layout, it works, but I'm trying to not change my homepage route if possible.
I've tried leaving path off, putting an absolute path, using nested IndexRoutes (doesn't work). Is there still a way to do this in RR 1.0?
export const routes = (
<Router history={createBrowserHistory()}>
<Route path="/" component={App}>
<Route component={DefaultLayout}> // Requires `path` Here
<IndexRoute component={Home} />
<Route path="about" component={About} />
<Route path="contact" component={Contact} />
<Route path="careers" component={Careers} />
</Route>
<Route path="blog" component={BlogLayout}>
<IndexRoute component={BlogHome} />
<Route path="posts/:post_name" component={BlogPost} />
</Route>
</Route>
</Router>
);
If I understood you correctly, your routes should look like:
export const routes = (
<Router history={createBrowserHistory()}>
<Route component={App}>
<Route path="/" component={DefaultLayout}> // Requires `path` Here
<IndexRoute component={Home} />
<Route path="about" component={About} />
<Route path="contact" component={Contact} />
<Route path="careers" component={Careers} />
</Route>
<Route path="blog" component={BlogLayout}>
<IndexRoute component={BlogHome} />
<Route path="posts/:post_name" component={BlogPost} />
</Route>
</Route>
</Router>
);

React-Router: Adding in a landing page

With React-Router there is a nesting concept that makes it hard for me to imagine where I should inject my landing page.
For example:
<Route path="/" component={App}>
<Route path="login" component={Login} />
<Route path="logout" component={Logout} />
<Route path="about" component={About} />
<Route path="dashboard" component={Dashboard} onEnter={requireAuth} />
</Route>
In that example part of the top-level component is shared with the rest of the components.
But with a landing page, there might not be the parent-child relationship for you to fit it into the routing.
Ergo, how do you manage putting in a landing page when using react-router?
Ok, let me answer here then.
The way you could do it is pretty straight forward, I think, if I understood you correctly.
I would do something like:
<Route path='/' component={LandingPage}>
<Route path='app' component={App}>
<Route path="login" component={Login} />
<Route path="logout" component={Logout} />
<Route path="about" component={About} />
<Route path="dashboard" component={Dashboard} onEnter={requireAuth} />
</Route>
</Route>
and then only include this.props.children in your App component.
I couldn't get any of the above answers to work so I decided to just do it my way. Here is what I did:
<Route path="/">
<IndexRoute component={Landing}/>
<Route path="/" component={App}>
<Route path="login" component={LoginOrRegister} onEnter={redirectAuth}/>
<Route path="dashboard" component={Dashboard} onEnter={requireAuth}/>
<Route path="vote" component={Vote} onEnter={requireAuth}/>
<Route path="about" component={About}/>
</Route>
</Route>
The Main component contains the minimal required for both the landing page and the App itself. In my case, they share nothing so the component is simply a wrapping div.
const Main = ({children}) => {
return (
<div>
{children}
</div>
);
};
Ran into this with the latest version (v6) of react-router-dom which no longer supports IndexRoute. After trying a few different approaches, it turned out to be relatively simple to add to the final catch-all where we normally specify our 404 page...
<Switch>
<Route
path="/learn?"
component={Learn}
/>
<Private
path="/search?"
component={Search}
/>
<Route
component={match.isExact ? Landing : Lost}
/>
</Switch>
This is within a top-level Application component that handles the root (/) path so match.isExact means we're on the home page. Above and below the <Switch> you can render any elements present on every page (e.g. a header and footer).
Hope this helps anyone coming across this question in 2022 and beyond.
React-router V6 supports index as an attribute of Route component
Index Route - A child route with no path that renders in the parent's outlet at the parent's URL.
See docs https://reactrouter.com/docs/en/v6/getting-started/concepts under "Defining Route" heading.
<Route path="/" element={<App />}>
<Route index element={<Home />} />
<Route path="teams" element={<Teams />}>
<Route path=":teamId" element={<Team />} />
...
</Route>
</Route>
</Routes>```
The IndexRoute in React-Router lets you define the default component when reaching a portion of your application. So with the following code, if you go to "/", the page will render the App component and inject the LandingPage component into its props.children.
<Route path="/" component={App}>
<IndexRoute component={LandingPage} />
<Route path="login" component={Login} />
<Route path="logout" component={Logout} />
<Route path="about" component={About} />
<Route path="dashboard" component={Dashboard} onEnter={requireAuth} />
</Route>

Categories