React Router, 2 routes with similar urls - reactjs

I have the following 2 routes:
<RouteEx path="/:id" component={Page2} />
<RouteEx path="/imprint" component={Imprint} />
Every time I click on imprint to navigate to my imprint page, I get an error in my console from Page2 component. How do I prevent calling Page2 when I want to navigate to Imprint page?

The "Route Matching" section of the React-Router documentation provides some tools for dealing with routes that can both serve as matches to the address text. The first is <Switch>, which makes it so that only one route--the first match, even if there are many--responds to the route match. Another is the exact property, which guarantees that a route won't be flexibly interpreted. In your case, you might use them both (though I think the exact tag may not be necessary in your case):
<Switch>
<RouteEx exact path="/imprint" component={Imprint} />
<RouteEx path="/:id" component={Page2} />
</Switch>
In this configuration, if the route matches '/imprint', it will not trigger the '/:id' route. This will work even if the id is a string. (Naturally, you'd have to make sure that you never encounter the case id === 'imprint'.)

If id is a number, then you can try using Regex :
<RouteEx exact path="/:id(\d+)" component={Page2}/>
<RouteEx exact path="/imprint" component={Imprint}/>

Related

Can React Router make multiple Routes visible at once and encoded in URL at once (desirable solution not failure)?

React router has the usual code:
<Switch>
<Route exact path='/order/:id' component={() => <OrderPage/>}/>
<Route exact path='/schedule/:orderid/:piececode' component={SchedulePage}/>
<Route path='/login' component={LoginForm}/>
<Route path='/about' component={About}/>
<Route path='/sales/invoicelist' component={InvoiceListPage}/>
<Route path='/sales/invoice' component={InvoicePage}/>
</Switch>
which facilitates, that one component (as specified in the Route that corresponds to the current URL) is instantiated and made visible in the React app.
But one can image the use cases when several root-level components should be made visible/available at once, like:
Multi-tab applications: the user wants to work with multiple invoices at once and she is opening multiple invoices in the app-level-tabs (not browser level) - each invoice in each page. So, she can keep editing one invoice while looking data from the other invoice. At the end of the session the use copies URL and sends via email to the collegue - she expects that collegue will be able to open the eaxact those pages;
stock trading application with multiple visible componens - share prices, data entry components for multiple stocks etc.
Does React Route has the capability to shoe multiple compoents and once and accept the URL which is concatenation (or some other combination) or multiple routes?
I have searched SO for this and there are similar questions, but all of them perceive such situation as the failure, e.g. they start to use Switch to show only one component.
Does React Router has capability for multiple visible routes and how such capability can be used?
Sure, let's take for example
<Route exact path='/order/:id' component={() => <OrderPage/>}/>
Your component OrderPage can have nested Route & Switch
const OrderPage = () => {
return (<>
<div>
....
</div>
<Switch>
<Route exact path='/order/:id/tab1' component={Tab1}/>
<Route exact path='/order/:id/tab2' component={Tab2}/>
</switch>
</>)
}
And to have this to work, and properly propagate url params, you need to remove the exact prop on your first route, and have all available url in your main route path
<Route path={['/order/:id/tab1', '/order/:id/tab2', '/order/:id']} component={OrderPage}/>
The correct answer is NO. Through react-router you can not have multiple concatenated URL's at the same time to render multiple pages.
But this can be achieved by designing the routes in a proper way such as for the example
Multi-tab applications: the user wants to work with multiple invoices
at once and she is opening multiple invoices in the app-level-tabs
(not browser level) - each invoice in each page. So, she can keep
editing one invoice while looking data from the other invoice. At the
end of the session the use copies URL and sends via email to the
collegue - she expects that collegue will be able to open the eaxact
those pages;
<Route exact path={['/order/:id/', '/order/:id/:refenceId']} component={() => <InvoicePage/>}/>
In this case, you can check if URL has referenceId then render the referenced invoice.
OR
By using query-paramters.
https://reactrouter.com/web/example/query-parameters
Add the referencedId in the query param and that can be shared
Through query-param it can even support your second usecase.
Switch component renders only one child route that matches current location. So if you want to render multiple Route components that match current location at once, you have to omit Switch.
For example, if you want both SalesPage and InvoicePage being rendered for /sales/invoice path you could do the following:
<>
<Route path='/sales' component={SalesPage}/>
<Route path='/sales/invoice' component={InvoicePage}/>
</>

Adding component to page when more specific route is used

What I'm trying to do is to display User details next to the table of users.
The user table is displayed on /users route and when I go to /users/0 I want to display both, the user table, and component User with the user's details.
Here is what I tried to do: https://codesandbox.io/embed/react-router-redirects-typescript-fg8yf
This, however, displays only a blank page when I try to navigate to the user's details.
Can anyone explain to me what I'm doing wrong, please?
You have provided exact prop here,
<Route exact path="/users" component={Users} />
When you provide exact prop, it will only match the path /users and not anything else. So when you give path /users/0 it will not navigate, because there is no matching Route present.
You need to remove the exact prop,
<Route path="/users" component={Users} />
Read more about exact prop.

React Router: How to match indeterminate amount of sub paths of a nested route?

I'm trying to create a file explorer like Dropbox. There will be an indeterminate amount of subpaths that look like this:
localhost:3001:file-manager/folder1/folder2/...folderN
I have this:
<Route path="/file-manager/:folderName" component={LandingPage} />
This allows me to visit: http://localhost:3001/file-manager/foo/bar/baz. However, when I check props.match I don't see it, it only shows a match for foo, not the levels below that (bar and baz).
match:
isExact: false
params: {folderName: "foo"}
path: "/file-manager/foo"
url: "/file-manager/foo"
How would I do this? All the tutorials I'm reading and watching about recursive routes append to the view. I want to replace the view.
I had the exact same problem a few months ago. I can't find the exact code I used at the moment, but if I recall correctly you can use an asterisk to indicate "everything from this point on" which includes any further path separators:
<Route path="/file-manager/:folderName*" component={LandingPage} />
This does mean that props.match.params.folderName will be the full string, so you'll have to split it by / yourself if you need an array of path components.
Important note: the * will make it match anything, so if you have a specific route you want to match, make sure you put it before this one, e.g.
<Route path="/file-manager/example" component={ExamplePage} />
<Route path="/file-manager/:folderName*" component={LandingPage} />
I think that what's happening is somehow correct since you're only defining one level of nested routes in the route declaration:
<Route path="/file-manager/:folderName" component={LandingPage} />
Therefore the first path param that is found (in your case foo) is matched against the folderName property, while others are ignored.
I've never done a thing like this but I can only imagine it to work using a dynamic route definition. Of course this works only if your app will render the same component for all the routes generated since the first one.
<Route path={`${this.props.match.url}/:folderName`} component={LandingPage} />
Something like this should prevent the problem you reported. But you must put an external route definition to start the route recursion. And in this case yours is going to be good.
<Route path="/file-manager/:folderName" component={LandingPage} />
You can find a similar thing over here at the chapter Recursive Routes.
Hope this helps!

Can react router have a route with multiple option parameters where (e.g.) both are required, or none

Using react-router-dom I have a route like so:
<Route path='/:year?/:month?' component={ThingUsingYearAndMonth} />
But really I want BOTH year and month to exist (e.g. /2018/Dec or /2017/Jan) or neither. I.e. just /2018 wouldn't match
I would probably handle that using two routes -- one for when both are provided and one for when neither are provided:
<Route path='/:year/:month' component={ThingUsingYearAndMonth} />
<Route path='/' exact component={ThingUsingYearAndMonth} />
Try providing explicit parameters with regex:
<Route path='/:year(\\d{4})?/:month([A-Za-z]+)?' component={ThingUsingYearAndMonth} />
I don't think there is any mechanism provided by the react-router-dom to validate the route params. You are better off creating your own Higher Order Component and validate the route params in it. Or you can use regex to validate your params in the route itself.

How do I avoid rendering a component when another component in a similar path has already rendered when using URL params in React Router v4?

I'm trying to create RESTful routes for my application, but I'm having problems when it comes to routes with URL params.
Here are the routes that I want to have:
/accounts
/accounts/new
/accounts/edit
/accounts/:id
These is what my router looks like:
<Router>
<Route exact path="/accounts" component={AccountsList} />
<Route exact path="/accounts/new" component={AccountCreate} />
<Route exact path="/accounts/edit" component={AccountUpdate} />
<Route exact path="/accounts/:id" component={AccountDetail} />
</Router>
/accounts works fine, but when I go to /accounts/new or /accounts/edit, it also renders AccountDetail which is supposed to be located at /accounts/:id.
For the record, that I get that this is the correct behavior since /accounts/:id technically matches /accounts/new and /accounts/edit.
My question is if there's a way to make :id match with a specific pattern only (numbers only).
Try the < Switch> component of reactRouter.
Renders the first child < Route> or < Redirect> that matches the
location.
I think it's exactly what you are looking for.

Resources