React route does not detect nesting routing and ids - reactjs

I have some React routes that when I nest one route inside another, I need to repeat the route path.
To explain, for example:
<Route
path="admin">
<Switch>
<Route
path="admin/specific/:id"
component={SpecificAdmin} />
<Route
exact
path="admin"
component={AdminPage}>
</Route>
<Route
exact
path="admin/edit/new"
component={EditSpecificAdmin} />
</Switch>
</Route>
I want a page where I can see the list of items, one for adding a new one and another for looking, editing a specific item. So I thought about the paths edit/new and specific/1.
So the routes do not detect when I write specific/1 (the specific id) and not either the admin nesting, so I need to write the admin in each one...

As Tareq aziz said, you can easily have intel in props.
You can create another router to pass easily new value:
// your original component
import AdminRouter from './Admin/Router';
export default () => {
return (
<Route path="admin">
<AdminRouter />
</Route>
);
}
// in ./Admin/Router.js
export default (props) => {
return (
<Switch>
<Route
exact
path={`${props.match.path}/specific/:id`}
component={SpecificAdmin}
/>
<Route
exact
path={`${props.match.path}`}
component={AdminPage}
/>
<Route
exact
path={`${props.match.path}/edit/new`}
component={EditSpecificAdmin}
/>
</Switch>
);
}
I'm not sure though if the order of the routes are correct.

I think you can get your current page's url from props using location.pathname or match.url. You can see my image. Then you may add your nested route after that. Hope it will help you
You may code your path like this way
path=`${this.props.location.pathname}/edit/new`
path=`${this.props.location.pathname}/specific/:id`

Related

why two routes calling same page in react js that has different path link

<Route path={${process.env.PUBLIC_URL}/book-repair/:name/:name} component={Modals}/>
<Route path={${process.env.PUBLIC_URL}/book-repair/:name} component={Companies}/>
when call second route this is calling very well. but when am call first route first route and second route both are calling. please solve my issue.
Use Switch to render the Routes Exclusively and use exact to strictly match the pattern
import { Route, Switch } from "react-router";
let routes = (
<Switch>
<Route path={${process.env.PUBLIC_URL}/book-repair/:name/:name} component={Modals} exact />
<Route path={${process.env.PUBLIC_URL}/book-repair/:name} component={Companies} exact />
</Switch>
);
Refer: https://reactrouter.com/web/api/Switch
<Switch><Route path={${process.env.PUBLIC_URL}/book-repair/:name/:name} exact component={Modals}/>
<Route path={${process.env.PUBLIC_URL}/book-repair/:name} exact component={Companies}/> </Switch>
You should add exact and Switch to your routes.
If you are rendering the routes into a Router they both can be matched and rendered. The Router inclusivley matches and renders routes. Use the exact prop to exactly match one or the other. The issue is that ${process.env.PUBLIC_URL}/book-repair/:name is a prefix for ${process.env.PUBLIC_URL}/book-repair/:name/:name, and so will also be matched.
<Route
exact
path={`${process.env.PUBLIC_URL}/book-repair/:name/:name`}
component={Modals}
/>
<Route
exact
path={`${process.env.PUBLIC_URL}/book-repair/:name`}
component={Companies}
/>
The alternative is to render the routes into a Switch to exclusively match and render routes. Here path order and specificity matter. Order your routes from most specific to least specific. You don't need to specify the exact prop since the Switch only matches and renders the first matching Route.
<Switch>
...
<Route
path={`${process.env.PUBLIC_URL}/book-repair/:name/:name`}
component={Modals}
/>
<Route
path={`${process.env.PUBLIC_URL}/book-repair/:name`}
component={Companies}
/>
...
</Switch>

React router does not render route when URL accessed directly

Consider this the main App component (imports left out for brevity):
const App = () => {
const [orderRoutes, setOrderRoutes] = useState([])
const updateOrderRoutes = (newRoute) => {
orderRoutes.push(newRoute)
setOrderRoutes(orderRoutes)
}
const renderedOrderRoutes = orderRoutes.map(route => {
return (
<Route
path={`/${route.class}/${route.order}`}
exact
key={`/${route.class}/${route.order}`}
>
<CatalogPage />
</Route>
)
})
return (
<BrowserRouter>
<Header
updateOrderRoutes={updateOrderRoutes}
/>
<Route path="/" exact component={Home} />
<Route path="/aboutus" exact component={AboutUs} />
<Route path="/faq" exact component={Faq} />
<Route path="/register" exact component={Register} />
{renderedOrderRoutes}
<Footer />
</BrowserRouter>
)
}
export default App
The challenge is that some of the routes are not known when rendering the initial App component. They will be known when an AJAX request in the <Header> component is responded to. The header will then update the new route to the orderRoutes state property, re-rendering the App component every time. The routes that are the result of the AJAX call (that is made in the <Header>) are then rendered to the <BrowserRouter> (in {renderedOrderRoutes}). In the <Header>, there is a <Link> for each route being rendered as a result of the same AJAX call, so that every menu entry (The <Link>s) will have a corresponding route.
This works fine, but when I access one of the URL's that this mechanism generates directly (e.g.: refresh the page), the <CatalogPage> component is not rendered.
So, for instance let's say that the AJAX call results in a bunch of routes and one of those is /t-shirts/tanktops. I will get a menu entry with a link to that path. When I click that menu entry the <CatalogPage> component is rendered. But when I access /t-shirts/tanktops directly, the <CatalogPage> component is not rendered.
How can I alter this code to make the URL's that are a result of the AJAX call directly accessible?
EDIT
OK, I 'solved' this (don't like it) by forcing the <App> component to re-render when one of the <Link>s was clicked by creating an unused piece of state on the App component called activeOrderRoute. I passed the setter down to the Header as a prop and connected it as a callback to the onClick handler for each Link that was created in response to the AJAX request. This essentially forces the App to re-render and render the routes, which solved my problems.
Still, that does not seem like the correct way to do it so any help would be appreciated.
React router does not directly have routing support for all URLs. It catches the default domain only the remaining routing is done on client side and requests are not served.
If your domain is www.mydomain.com, you can not access the URL www.mydomain.com/info directly in the react router.
Solutions:
You can use a hash router but that makes the URLs unfriendly for SEO
You can set up a catch-all routes and route it yourself
This link would help you with the same
https://ui.dev/react-router-cannot-get-url-refresh/
you need to modify your webpack.config.js and add the following lines.
module.exports = {
devServer: {
historyApiFallback: true,
},
...
Instead of trying to explicitly render a route for each asynchronously fetched route, leverage the power of react-router-dom and render a dynamic route path string that can handle any catalog page.
Instead of this:
const renderedOrderRoutes = orderRoutes.map(route => {
return (
<Route
path={`/${route.class}/${route.order}`}
exact
key={`/${route.class}/${route.order}`}
>
<CatalogPage />
</Route>
)
})
return (
<BrowserRouter>
<Header
updateOrderRoutes={updateOrderRoutes}
/>
<Route path="/" exact component={Home} />
<Route path="/aboutus" exact component={AboutUs} />
<Route path="/faq" exact component={Faq} />
<Route path="/register" exact component={Register} />
{renderedOrderRoutes}
<Footer />
</BrowserRouter>
)
Render a single dynamic route in your Router. Use a Switch so only a single route component is matched and rendered. Reorder the routes so the more specific paths can be matched before less specific paths. Now, when a URL has a path that is of the shape "/someClass/someOrder" it can be matched before you try matching any of the more general paths. You will see that the home path ("/") is matched last and the reordering allows us to remove the exact prop on all routes.
return (
<BrowserRouter>
<Header updateOrderRoutes={updateOrderRoutes} />
<Switch>
<Route
path="/:class/:order"
exact
component={CatalogPage}
/>
<Route path="/aboutus" component={AboutUs} />
<Route path="/faq" component={Faq} />
<Route path="/register" component={Register} />
<Route path="/" component={Home} />
</Switch>
<Footer />
</BrowserRouter>
)
You may need to adjust some logic in CatalogPage to handle possible undefined catalog data, whatever it is using from the route props/etc... to render catalog stuff.
In your Header component make the asynchronous call there to fetch the routes that can be navigated to so you can dynamically render render links to them (if that is even why you are passing the routes to Header).

Is there such a thing like sass mixins in react?

So I have a react application that involves a lot of routing and this routings are done based on conditions. For example if a user logs in then some of the paths might mean something different than what they would mean if the user wasn't logged in. Here is a simple example.
<Switch>
(this.state.isAuthenticated)?
this.state.game?
<Route path="/game/Game91" render={(props) => <Game91 {...props} games={this.state.allGames} />} />:
<Route path="/game/Game91/" render={(props) => <CreateGame {...props} game="game91" />} />:
<Route exact path="/game/Game91" render={(props) => <LoginForm {...props} onGuestLogin = {this.guestLogin} parentLocation = "/game/Game91" />} />
}
</Switch>
...
So in the above code if a user is authenticated and if the game is choosen then I want the url /game/Game91 to take the user to the Game91 component. If the user is authenticated but a game isnt choosen I want /game/Game91 to take the user to the create game component and so forth. And this has been workign for me for now. I unserstand this might not be the best practice out their, so I would be glad if you share what the best practices are in such scinarios and send me links to more reads. But my main question for now is that what if I have another path like /somepath/to that also means different things like the /game/Game91. To do, that I will have to rewrite all the above code since I can't fit all this in one ternary operator. Hypotetically this is what I would like.
<Switch>
(this.state.isAuthenticated)?
this.state.game?
<Route path="/game/Game91" render={..something..} />
<Route path="/somePath/to" render={..something..} />
:
<Route path="/game/Game91" render={..somethingElse..} />
<Route path="/somePath/to" render={..somethingElse..} />
:
<Route path="/game/Game91" render={..something..} />
<Route path="/somePath/to" render={..something..} />
}
</Switch>
But the above isn't possible because a ternary operators can't return more than one thing. and I cant use if statments beacuse JSX doesn't allow them. So ideally if I could have function that will return this pair of things without wrapping them in any kind of container like you would with scss mixins that would be great. So is there such a thing in react or are there other better ways to do such things?
Generally every page or container should be addressed to only one route path. Instead of changing the component at runtime by checking the flags, you can navigate from one route to another based on your conditions using react hooks.
Note:
This example uses react router v6. If you are using the v5.2 version of react router, then you need to use history api instead of navigate.
useEffect(() => {
if (isAuthenticated) {
if(isGameActive)
navigate('/gaming');
else
navigate('/create-game');
}
else {
navigate('/login');
}
}, [isAuthenticated]);
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/gaming" element={<Game91 />} />
<Route path="/create-game" element={<CreateGaming />} />
</Routes>
</Router>
react-router v6

react router duplicated URL params

I know this issue has to do with a fundamental misunderstanding of how React Router works, and more specifically, probably the history object. I have a component called Search, which lets the user search for a particular city. This component appears in multiple places throughout the app, including '/' and '/:cityname'.
From '/', the component works as expected, and correctly pushes the new url param onto the url and the url becomes '/vancouver'. However, from '/vancouver', when I use this same component, the url does not behave as expected. For instance if I enter Istanbul, I am correctly directed to /istanbul, but then as I proceed through the app and click on items, I expect to be directed to '/istanbul/item1'. However, what happens currently is that I end up at '/istanbul/istanbul/item1', which of course is not found, and returns a 404.
Here is the function that gets called when a city is selected (found within Search component)
const onSuggestionSelected = (event, { suggestion }) => {
props.history.push(`/${suggestion.nickname}`)
}
App.js with routes
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/terms-of-service" component={TermsOfServicePage} />
<Route exact path="/privacy-policy" component={PrivacyPolicyPage} />
<Route exact path="/:cityname/personalize" component={FilterPage} />
<Route exact path="/:cityname/experiences" component={SearchPage}>
<Redirect to="/:cityname" />
</Route>
<Route exact path="/:cityname" component={SearchPage} />
<Route exact path="/:cityname/experiences/:experiencename" component={ExperiencePage} />
<Route exact path="/:cityname/experiences/:experiencename/summary" component={(routeProps) => <SummaryPage {...routeProps} />} />
<Route exact path="/:cityname/experiences/:experiencename/payment" component={PaymentPage} />
<Route exact path="/:cityname/experiences/:experiencename/payment-successful" component={PaymentSuccessfulPage} />
<Route component={NotFoundPage} />
<GlobalStyle />
</Switch>
ExploreMore Button
<ButtonWrapper onClick={sendAnalyticsData}>
<LetsGoButton to={{
pathname: `${props.match.params.cityname}/experiences/${experience.nickname}`,
state: props.location.state
}}
palette="tertiary">
Explore more
</LetsGoButton>
</ButtonWrapper>
Please let me know if there is anything else that I can provide that would be helpful. I've tried to do research on how history.push works exactly, but I haven't been able to find much. My best guess is that it takes the current location, and adds on the provided url. Even if that's the case, I can't understand why it would be applying istanbul twice.
I figured out the problem on this one. One of the commenters suggested that I had been using relative paths rather than absolute. I erroneously thought that he was incorrect, seeing as I seemingly have the full url in there. My mistake was to not start off the url with /
before:
${props.match.params.cityname}/experiences/${experience.nickname}
after:
/${props.match.params.cityname}/experiences/${experience.nickname}
I hope this helps someone out.

nested routes with optional parameter

Hi there for localization reasion i need optional nested routes like /en/mypage , /ru/mypage , /my page, I already tried to work with <Route but didn't get it working.
<Route path="/:lang(en|lt|ru)?" >
<Route path="/surveys" exact component={Dashboard} />
</Route>
Already found solutions above with earlier versions but it doesn't seem working now. How can i implement it? i know it's posible to add to every route parameter, but isn't here more elegant way.
You can't nest your routes in React-Router v4. Instead you should add nested routes in component or use render prop:
<Route path="/:lang(en|lt|ru)" render={({ match: { url } }) => (
<>
<Route path={`${url}/surveys`} component={Dashboard} exact />
</>
)}
/>
In above example your available routes would be
/en/surveys
/lt/surveys
/ru/surveys

Resources