React Router modify URL if all params are not passed - react-router

I am trying to fix an issue in my app where I need to modify the URL when all route params are not entered in the URL by the user.
This is what my router looks like:
<Switch>
<Route path="/A" exact strict component={T3} />
<Route path="/B" exact strict component={BestOf} />
<Route path="/C/:id" component={Author} />
<Route path="/D" exact strict component={About} />
<Route path="/E" exact strict component={ContactUs} />
<Route path="/F/:id/:subId" exact strict component={Careers} />
<Redirect to="/"
</Switch>
What happens: If I enter in URL bar http://localhost:3000/F/1, the app redirects to /.
What I want: I want to change such URLs to http://localhost:3000/F/1/0
I tried to use another Switch inside Switch to handle this, but I am not getting desired results.
Any help would be appreciated.
Thanks in advance.

What would could do is to make the url params optional and in Careers component redirect to the valid default url
<Switch>
<Route path="/A" exact strict component={T3} />
<Route path="/B" exact strict component={BestOf} />
<Route path="/C/:id" component={Author} />
<Route path="/D" exact strict component={About} />
<Route path="/E" exact strict component={ContactUs} />
<Route path="/F/:id?/:subId?" exact strict component={Careers} />
<Redirect to="/" />
</Switch>
now in Careers component render method
render() {
const { match: { params }} = this.props;
if (!params.id || !params.subId ) {
return <Redirect to=`${match.url}/0/0` />
}
// rest code here
}

Related

react-router-dom switch not rendering components after dynamic path

I`ve been following an e-commerce tutorial and building on top of it. Im new to React and React Router Dom.
I've set a dynamic path for individual product pages, and now i' trying to add some new paths i.e. contact, about, etc.. If I add the new paths above the dynamic path they are rendered properly, but if I place the routes under the one with the dynamic path, for example the /hello, they won't render. Is this normal behaviour??
<Router>
<div>
<Navbar totalItems={cart.total_items} />
<Switch>
<Route exact path="/">
<Home products={products} handleAddToCart={handleAddToCart} fetchProduct={fetchProduct} />
</Route>
<Route exact path="/checkout">
<Checkout cart={cart} order={order} handleCaptureCheckout={handleCaptureCheckout} error={errorMessage} refreshCart={refreshCart} />
</Route>
<Route exact path="/cart">
<Cart
cart={cart}
handleUpdateCartQuantity={handleUpdateCartQuantity}
handleRemoveFromCart={handleRemoveFromCart}
handleEmptyCart={handleEmptyCart}
/>
</Route>
<Route exact path="/contact">
<Contact />
</Route>
<Route exact path="/:id">
<Details product={product} handleAddToCart={handleAddToCart} />
</Route>
<Route exact path="/hello">
<h1>Hello World</h1>
</Route>
</Switch>
</div>
<Router>
Yes, this behavior is completely normal, and expected. Recall that the Switch component "Renders the first child <Route> or <Redirect> that matches the location." This means that in the Switch component path order and specificity matter!
A path "/hello" is more specific than "/:id", so depending on route order may or may not be matched first. Or in other words, "/hello" can always be matched to "/:id", but not always the other way around.
You should always order the routes from more specific paths to less specific paths, and if done correctly there should be a near zero need for the exact prop.
"/hello" is more specific than "/:id" which is more specific than "/".
<Switch>
<Route path="/checkout">
<Checkout ... />
</Route>
<Route path="/cart">
<Cart ... />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/hello">
<h1>Hello World</h1>
</Route>
<Route path="/:id">
<Details ... />
</Route>
<Route path="/">
<Home ... />
</Route>
</Switch>
If you had a nested "/contact/add" route for example, this is more specific than "/contact" and should be listed higher/before in the Switch.
Try removing the exact from the Route.
<Route exact path="/:id">
to:
<Route path="/:id">

React router path as an array

I have a code like this :
<BrowserRouter>
<Switch>
<Route path="/" exact component={component1} />
<Route path="/somewhere/:something" component={component2} />
</Switch>
</BrowserRouter>
I tried this, because in the end, I want to match several paths with the same component / result :
<BrowserRouter>
<Switch>
<Route path={["/somewhere/:something","/somewhere2/:something"]} component={component2} />
</Switch>
</BrowserRouter>
and the path is matched, but my parameter (:something) isnt passed to it. Any idea why ? react-router's docs tells me :
Any valid URL path or array of paths that path-to-regexp#^1.7.0 understands.
The feature was only recently added to React-Router. You need to upgrade your react-router installation to be able to match the documentation and use the feature.

Is there a way to define default route (if no one match) in react-router-redux#5.0.0

Im using react-router-redux#5.0.0
I have this
<Route path='/login' component={ Login } />
<Route exact path='/' component={ Home } />
Is there a way to define default route as in react-router-redux#4.x.x?
It is also necessary this "default route" does not pass if any other matched.
Because if I will add
<Route path='/login' component={ Login } />
<Route exact path='/' component={ Home } />
<Route component={ Default } />
Default component will be rendered for all routes, including '/login' and '/'
I was looking for answer for the same problem but for react-router-dom package. The solution was this:
<Switch>
<Route path='/login' component={ Login } />
<Route exact path='/' component={ Home } />
<Route component={ Default } />
</Switch>
This way the first Route that matches will be displayed while the rest ignored.
You can import Switch together with Route like this:
import { BrowserRouter, Switch, Route } from 'react-router-dom';
Place the following catch-all route after all other routes are defined (optionally leave the path out as stated below):
<Route path="*" component={DefaultRoute} />
Here's a link to an answer with more details: React-Router: No Not Found Route?
With latest react-router version,
<Route path='' Componenet={Default}>
should be changed to,
<Route path='' element={<Default>}>

Conditional rendering with React Router

I'd like to render some routes with a nav at the top, while rendering other routes (like a sign-up / sign-in page) without any nav.
For the setup with the nav, I have:
const App = () => (
<Router>
<div>
<Nav />
<div>
<Route exact path="/" component={Home} />
<Route path="/account" component={Account} />
<Route path="/news" component={News} />
</div>
<Footer />
</div>
</Router>
);
I'm trying to find the best way of handling this with React Router (seems like it would have to handled with some type of conditional maybe? - "if my current route matches any one of these routes, then render like so else render this.").
Thanks!
You have at least two possibilities:
Use Route "path" property to test the route and render the component. Path property accepts path.to.regexp expressions.
Wrap your component with withRouter method and inside Nav test if the route matches and render null otherwise.
First answer:
const App = () => (
<Router>
<div>
<Route path="/(?!signin|signup)" component={Nav}/>
<div>
<Route exact path="/" component={Home} />
<Route path="/account" component={Account} />
<Route path="/news" component={News} />
</div>
<Footer />
</div>
</Router>
);
Second answer:
import { withRouter } from 'react-router'
const NavWithRouter = withRouter(Nav);
const App = () => (
<Router>
<div>
<NavWithRouter/>
<div>
<Route exact path="/" component={Home} />
<Route path="/account" component={Account} />
<Route path="/news" component={News} />
</div>
<Footer />
</div>
</Router>
);
<Route
path={`foo/(A|B|C)`}
component={() => (<Baz {...props}/>)}
/>
Where A,B,C are the different routes like foo/A.
I usually use two different Layout pages. And within the Layout pages, have a router for the content.
My code will look like this:
<Router>
<Route path="/login" component={AuthLayout} />
<Route path="/logout" component={AuthLayout} />
<Route path="/some/path" component={Layout} />
</Router>
Within each Layout, there will be the usual header / footer / navbars and then another set of routes.
<div className="auth-layout">
<header className="auth-layout__header"></header>
<main className="auth-layout__content">
<Switch>
<Route path="/login" component={Login} />
<Route path="/logout" component={Logout} />
</Switch>
</main>
</div>
In this way, I have a direct mapping from requirements to code. In my code, there are much more differences between the two layouts.
Just use a prop for this & inside the children your are able to conditional render the nav.
<Route exact path="/" render={() => <Home hasNav={false} />}

How to render specific component when route change using React Router 4?

I have following route,
<Route exact path ='/' component={Posts} />
<Route exact path ='/:category' component={Posts} />
<Route exact path ='/new' component={NewPost} />
issue is when I go to /new route, Post component is getting rendered as well along with NewPost component. How to avoid that?.
I had to wrap route inside Component. It worked.
import { Route, Switch } from 'react-router-dom'
<Switch>
<Route exact path ='/' component={Posts} />
<Route exact path ='/:category' component={Posts} />
<Route exact path ='/new' component={NewPost} />
</Switch>