React Router v4 Nested Routing not working when in sub level - reactjs

I'm trying to build a React App, this is the first time i'm working with react and so i don't know how to troubleshoot this. Basically what i need is to create routes for a link, let's say these are the following links.
/car
/car/sedan
/car/coupe
i have setup routing as so.
car.js
import React from 'react'
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom'
import CoupeCar from './coupecar'
import SedanCar from './sedancar'
class Car extends React.Component {
constructor(props){
super(props);
}
render () {
return (
<div className="main_elem_container">
<Router>
<Switch>
<Route path="/car" component={Car} />
<Route exact path="/car/sedan" component={SedanCar} />
<Route exact path="/car/coupe" component={CoupeCar} />
</Switch>
</Router>
</div>
);
}
}
const Car = () => (
<p>I'm a Car</p>
)
export default Car;
And the routing works i can visit /car/sedan and /car/coupe when i'm browsing through the navigation from /car but i cannot visit /car/sedan when im at the /car/coupe page and vice-versa.
The navigation just gets stuck and doesn't load, please let me know on how i can fix this i've even tried many options but all of them give me this result, at least if i knew how to debug this it'll be better, thanks.

I don't know how your setup works partially, it should not with this config. What you need is:
<Router>
<Switch>
<Route exact path="/car" component={Car} />
<Route path="/car/sedan" component={SedanCar} />
<Route path="/car/coupe" component={CoupeCar} />
</Switch>
</Router>
So, if only when you hit /car your Car component renders. For /car/sedan and /car/coupe you will see the related components. If you don't use exact for /car, /car/sedan and /car/coupe will render Car component no matter what.
Also, do not use same component names. You have two Car components. Rename the container something else, App maybe?

try this, the exact path should be placed as last option
<Router>
<Switch>
<Route path="/car/sedan" component={SedanCar} />
<Route path="/car/coupe" component={CoupeCar} />
<Route exact path="/car" component={Car} />
</Switch>
</Router>

Related

From Next to CRA, routing and layout issues

I had a very swell project going on in Next.js but I decided to revert back to Create React App yesterday and ran into some issues along the way.
I'm trying to keep a persistent layout along the app pages, that are separated from the pages themselves. Yet they appear on every route, even the auth pages, which have their own layout. "/" will either show the landing page that shouldn't contain the AppLayout or the home/feed page that should, if the user is authenticated. I'm unsure at what level I should be approaching this.
Another thing is that the user's profile data should only return on "/:username", instead of it loading on all of the pages with a param in the base URL "/". I'm making unnecessary graphql calls on /explore, /notifications, etc from that route. I'm not trying to change it to anything else such as, /u/:username and would rather find a solution that works for my case, even if that means replacing my router library for something else.
Any insight would be appreciated, this is /routes/Router.js:
import { Route, Switch } from "wouter";
import Login from './auth/Login'
import Signup from './auth/Signup'
import Verify from './auth/Verify'
import Reset from './auth/Reset'
import Root from './Root'
import Explore from './app/Explore'
import Notifications from './app/Notifications'
import Messages from './app/Messages'
import Bookmarks from './app/Bookmarks'
import Lists from './app/Lists'
import Profile from './app/Profile'
import Settings from './app/Settings'
import AppLayout from "../components/AppLayout";
export default function Router() {
return (
<>
<Route path="/i/flow/login" component={Login} />
<Route path="/i/flow/signup" component={Signup} />
<Route path="/i/verify/:token" component={Verify} />
<Route path="/i/flow/reset/:token" component={Reset} />
<Route path="/i/flow/reset" component={Reset} />
<Switch>
<AppLayout>
<Route path='/' component={Root} />
<Route path='/explore' component={Explore} />
<Route path='/notifications' component={Notifications} />
<Route path='/messages' component={Messages} />
<Route path='/bookmarks' component={Bookmarks} />
<Route path='/lists' component={Lists} />
<Route path='/settings' component={Settings} />
<Route exact path='/:username' component={Profile} />
</AppLayout>
</Switch>
</>
);
}
Sorry, wouter doesn't seem to include an exact attribute so I don't think that will make a difference.
Also, I'm pretty sure AppLayout will be rendered regardless of which route is active because it itself is not in a route.
Instead do something like this for each route where you'd like it to appear:
<Route path='/'>
<AppLayout>
<Root/>
</AppLayout>
</Route>
Regarding the '/:username' issue, is it rendering the profile route every time regardless of the path?

Browser Router (React app ) on Github not working

i have a little React app project and i have deployed it in Github. It works, even i am using import { BrowserRouter, Link, Switch, Route } from "react-router-dom"; to routing and works ... for my home component but not for the rest. This is my code: `class App extends React.Component {
render() {
return <div>
<BrowserRouter basename={process.env.PUBLIC_URL}>
<Switch>
<Route exact path ="/" component={Show} />
<Route exact path="/contact" component={Contact}/>
</Switch>
</BrowserRouter>
</div>
}
}
export default App;`
I have used this in local machine without the "basename" and worked. Now, in the github server my problem is that it is currently showing my first component when you visit my app main url but is not working for the other component, "/contact". I am not sure if i have to use the '<Link to ' property. Anyway, i just want to know why is working for my main url path (https://namegithub.github.io/main-path/) but not for any other path (https://namegithub.github.io/main-path/contact).
Sorry is a dummy question but actually i am just giving my first steps in React.
Thanks!
you can you this code
import {BrowserRouter as Router,Switch,Route} from 'react-router-dom'
return <div>
<Router basename={process.env.PUBLIC_URL}>
<Switch>
<Route exact path ="/" component={Show} />
<Route exact path="/contact" component={Contact}/>
</Switch>
</Router>
</div>

history.push() updates URL in browser but does not renders the appropriate component(Redirect not working too)

I am using react-router in my project and using this.props.history.push() inside componentDidMount() if the user is not looged in ,then redirect him to Login component.
This is my code in App.js:
class App extends React.Component{
constructor(props){
super(props);
}
componentDidMount(){
firebase.auth().onAuthStateChanged((user)=>{
if(user){
this.props.dispatch(login(user.email));
}
else{
this.props.history.push('/login');
}
})
}
render(){
//console.log(this.props.isLoggedIn);
return (<div className="App">
<Switch>
<Route path="/" component={()=><Homepage userName={this.props.username} logout={this.logout}/>} />
<Route path="/login" component={Login} />
</Switch>
</div>);}
}
export default withRouter(connect(mapStateToProps)(App));
Below is my index.js code:
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import './index.css';
const store= createStore(combineReducers({userState: userState}),applyMiddleware(logger));
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
,
document.getElementById('root')
);
Please not that I have removed some unnecessary functions and imports irrelevent to the context of this question.
Now let us come to what I have tried till now:
Using Router instead of BrowserRouter with history object passed to it.
Tried removing switch but that didn't work too.
I also searched for other questions that address this problem but unfortunately, none of them worked for me.
Please help me to find if there is any issue in my code.
Thank You!!
EDIT:
Looks like I'm having a bad day, even Redirect isn't working for me!
I'm trying very hard but I don't understand why Login component is not being rendered even when the URL is being changed.
You need to use exact prop in your Route. Otherwise, /login will also match / first
<Route exact path="/" component={()=><Homepage userName={this.props.username} logout={this.logout}/>} />
<Route exact path="/login" component={Login} />
It seems like you didn't use exact in your Route component. If you don't use exact then react will route to / path first. It will reads the path(/login) as / + login.
If you provide exact to this / path then react will route to the specified component which exactly matches the path. It is not necessary to provide an exact to all the Route component.
It is necessary when:
For example,
<Route exact path="/" component={About} />
<Route path="/login" component={Login} />
Then you need to provide the exact to parent path.
<Route exact path="/login" component={Login} />
<Route path="/login/profile" component={Profile} />
In short, if your next Route component path is a child of the previous path then you need to provide the exact property to the parent path.
Edited: There is one more thing that I'd like to say that in your Route component of / path you must have a render prop instead of a component prop for rendering the Callback component like this.
<Route exact path="/" render={()=><Homepage userName={this.props.username} logout={this.logout}/>} />
Some credits to #Sohaib answer. I have added some more explanation to his answer.

Nested routing in React router 4

I have a component, App component, NewHome Component and Results component.
My route in component App looks like
<Route exact path="/" component={NewHome} />
<Route path="flights/search/roundtrip" component={Results} />
NewHome Routes look like
<Route path="/flights" component={FlightSearch} />
<Route path="/hotels" component={HotelSearch} />
Results component is class based react component
Only App component gets render, but component inside, I can see null in react devtools and Ui only has the part of App not part of results
<Route path="flights/search/roundtrip" component={Results}>
null
<Route />
Ideally, it should work, but I am not able to understand what I am doing wrong here. Any pointers or suggetions will be helpful. What can be the probable reasons for this kind of behaviour
This is the code where i am doing reactdom.render in index.js file
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<Route path="/" component={App} />
{/* {routes} */}
</ConnectedRouter>
</Provider>,
document.getElementById("root")
)
Note: full url is something like this
http://localhost:3001/flights/search/roundtrip?search_type=roundtrip&origin=BLR&destination=MAA&travel_date=2018-01-29&return_date=2018-02-13&class_type=ECONOMY&adult_count=1&child_count=0&residentof_india=true&infant_count=0&originAndDestinationSwapped=false&activeIndexMulticity=0
NewHome gets a match prop. With that, simply contact its url with nested routes you might need.
NewHome component:
render() {
const { match } = this.props
return (
<div>
<Route path={`${match.url}/flights`} component={FlightSearch} />
<Route path={`${match.url}/hotels`} component={HotelSearch} />
</div>
)
}
I think its because you forgot a '/' in your route.
try
<Route path="/flights/search/roundtrip" component={Results} />
instead of
<Route path="flights/search/roundtrip" component={Results} />
try exporting your component after wrapping your component in withRouter HOC
import { withRouter} from 'react-router-dom';
and export the component as follows
export default withRouter(Results);
I have found out the issue, in my app i was importing Route from react-router-dom. Its available in react-router. May be a correct error message would have helped :) Thanks #sujit and #mersocarlin for giving valuable inputs.

React Router always redirect me to a different url

I'm new to React and React Router. I'm using React Router v4 and following a tutorial based on previous versions - but I made it work (using some stuff found on SO and some stuff on the react router v4 docs).
There is one thing though that is bothering me.
I have a url http://localhost:3000/#/bugs, which basically loads a list of all my bugs. But I also have possible urls like http://localhost:3000/#/bugs?priority=low&status=open which loads a specific set of urls.
The urls themselves work and do the job as expected.
The werid thing is that whenever I type http://localhost:3000/#/bugs?priority=low&status=open (or any params), the component do their jobs but the URL address bar shows http://localhost:3000/#/bugs (although the rendering shows everything related to priority and status shown).
Somehow, the URL location bar is changed but I don't understand why.
Here is my App.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BugList} from './BugList';
import {Redirect} from 'react-router';
import {HashRouter as Router, Route} from 'react-router-dom';
const NoMatch = React.createClass({
render : function (){
return(
<h2>This path does not exist</h2>
);
}
});
ReactDOM.render(
(
<Router>
<div>
<Route path='/bugs' component={BugList}/>
<Route path='/bugs/priority/:priority' component={BugList}/>
<Redirect from='/' to="/bugs" />
<Route path="*" component={NoMatch} />
</div>
</Router>
),
document.getElementById('main')
);
Thanks in advance.
EDIT 12th of April. Despite of the precious help of someone below, this is still not solved. I tried using Switch inside a Router but it doesn't work at all (nothing is shown). So the problem is still happening, and this is the current state of my App.js, using react-15.5.3, react-dom-15.5.3, react-router-4.0.0 and react-router-dom-4.0.0....
import React from 'react';
import ReactDOM from 'react-dom';
import {BugList} from './BugList';
import BugEdit from './BugEdit';
import {Redirect} from 'react-router';
import {HashRouter as Router, Route} from 'react-router-dom';
const NoMatch = React.createClass({
render : function (){
return(
<h2>This path does not exist</h2>
);
}
});
ReactDOM.render(
(
<Router>
<div>
<Redirect from='/' to="/bugs" />
<Route path='/bugs' component={BugList}/>
<Route path='/bug/:id' component={BugEdit}/>
<Route path="*" component={NoMatch} />
</div>
</Router>
),
document.getElementById('main')
);
The problem is that even if you enter the URL with query this URL matches Redirect path (since it's just / any URL matches this pattern) so the redirection to /bugs occurs. You have to use Switch (remember to import it) to render only the first <Route> or <Redirect> that matches the URL:
<Router>
<Switch>
<Route path='/bugs' component={BugList}/>
<Redirect from='/' to="/bugs" />
...
</Switch>
</Router>
The problem occured only on page load and not on re-entering the URL because your routing is based on hashes and the browser doesn't reload page when only hash part changes.
Please note that Redirect component in React-Router v4 performs redirection only when it's rendered - it doesn't set up permanent redirection rule so in your case redirection works only on page load. If you'd like your app to always redirect given URL you'd have to define Route for URL you'd like to redirect from and render Redirect:
<Route path='/oldUrl' render={() => (
<Redirect to="newUrl" />
)}/>
Furthermore, React-Router v4 is quite different from v3 so I don't recommend using v3 tutorials - it doesn't make sense.
Building on what Bartek said: if you use Switch, it will go directional from top to bottom and render the first hit, since you moved your redirect to the first position it will always hit that first and then not go to the other routes. Which is why your Switch should look like this imho (untested):
<Router>
<Switch>
<Route path='/bugs' component={BugList}/>
<Route path='/bug/:id' component={BugEdit}/>
<Redirect from='/' to="/bugs" />
<Route path="*" component={NoMatch} />
</Switch>
</Router>
I know its 04/2020, but this will fix your issue.
<Switch>
<Route path='/bug/:id' component={BugEdit}/>
<Route path='/bugs' component={BugList}/>
<Redirect from='/' to="/bugs" />
<Route path="*" component={NoMatch} />
</Switch>
</Router>```

Resources