React route is not working | React Router using React-router-dom - react-router

**app.jsx is the main file handling all routes.**
<Switch>
<Route exact path="/" component={Home} />
<Route path="/entry-rules" component={EntryRules} />
<Route path="/entry-form" component={EntryForm} />
<Route path="/payment" component={Payment} />
<Route component={Error404} />
</Switch>
```
**Home route is working fine when I click others component is not working.**
**I have used react-router-dom version 5.2.0**
```
<li className="nav-item">
<Link to="/" className="nav-link active" aria-current="page">
Home
</Link>
</li>
<li className="nav-item">
<Link to="/entry-rules" className="nav-link">
Entry Rules
</Link>
</li>
<li className="nav-item">
<Link to="/entry-form" className="nav-link">
Entry Form
</Link>
</li>
```
Home route is working fine when I click others component is not working.
app.jsx is the main file handling all routes.
I have used react-router-dom version 5.2.0

Welcome to SO! I see you are using exact for the Home route but not for others. React Router Dom needs to be told that the path is exact, so you should do something like this:
<Switch>
<Route exact path="/" component={Home} />
<Route path="/entry-rules" exact component={EntryRules} />
<Route path="/entry-rorm" exact component={EntryForm} />
<Route path="/payment" exact component={Payment} />
<Route component={Error404} path="*" />
</Switch>
Notice how has '*' and no exact props. Since we want to Error404 component if RRD can't find anything from above.
Once again welcome to SO, try to structure your question nicely and upvote answers that are helpful.

There is typo in one of the Route. path should be "/entry-form"
<Route path="/entry-rorm" component={EntryForm} />
<Link to="/entry-form" className="nav-link">
For other routes it should be working with your code. If not, try moving Home page route below all routes inside <Switch> component

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 modify URL if all params are not passed

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
}

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>

Nested Routes in React Router v4

I'm trying to set up some nested routes to add a common layout. Check the code out:
<Router>
<Route component={Layout}>
<div>
<Route path='/abc' component={ABC} />
<Route path='/xyz' component={XYZ} />
</div>
</Route>
</Router>
While this works perfectly fine, I still get the warning:
Warning: You should not use <Route component> and <Route children> in the same
route; will be ignored
CESCO's answer renders first the component AppShell then one of the components inside Switch. But these components are NOT going to render inside AppShell, they will NOT be children of AppShell.
In v4 to wrap components you don't put anymore your Routes inside another Route, you put your Routes directly inside a component.
I.E : for the wrapper instead of <Route component={Layout}> you directly use <Layout>.
Full code :
<Router>
<Layout>
<Route path='/abc' component={ABC} />
<Route path='/xyz' component={XYZ} />
</Layout>
</Router>
The change is probably explained by the idea to make React Router v4 to be pure
React so you only use React elements like with any other React element.
EDIT : I removed the Switch component as it's not useful here. See when it's useful here.
You need to use the switch component to nesting to work nice. Also, see this question
// main app
<div>
// not setting a path prop, makes this always render
<Route component={AppShell}/>
<Switch>
<Route exact path="/" component={Login}/>
<Route path="/dashboard" component={AsyncDashboard(userAgent)}/>
<Route component={NoMatch}/>
</Switch>
</div>
And version-4 components do not take children, instead, you should use the render prop.
<Router>
<Route render={(props)=>{
return <div>Whatever</div>}>
</Route>
</Router>
Try:
<Router>
<Layout>
<Route path='/abc' component={ABC} />
<Route path='/xyz' component={XYZ} />
</Layout>
</Router>
If you do not want Layout to run at loaded. Use this method:
<div className="container">
<Route path="/main" component={ChatList}/>
<Switch>
<Route exact path="/" component={Start} />
<Route path="/main/single" component={SingleChat} />
<Route path="/main/group" component={GroupChat} />
<Route path="/login" component={Login} />
</Switch>
</div>
Whenever history changes, componentWillReceiveProps in the ChatList will run.
You can also try this :
<Route exact path="/Home"
render={props=>(
<div>
<Layout/>
<Archive/>
</div>
)}
/>