I'm trying to implement the React HashRouter from react-router-v4... It works perfectly when I navigate over the page when using all the buttons...
But on a Page refresh I get a strange behavior. May someone of you can help me. Here's my code:
<HashRouter basename='/app'>
<Route component={App} />
</HashRouter>
And then, my Router:
<Switch>
<Route path='/statistics' component={Statistics}/>
<Route path='/search' component={Search}/>
<Route path='/settings' component={User}/>
<Route path='/demo' component={Demo}/>
<Route path='/' component={Statistics}/>
<Route render={() => <SiteNotFound />} />
</Switch>
Whenever I reload the page, the "Statistics" component get rendered, because the http://localhost:8080/#/app/demo I expect the Demo component to be rendered, but I get the Statistics Component.
Can someone explain me this behavior?
Thanks
Use this <Route path='/' exact component={Statistics}/>
Related
I have the below swtich using react-router. When I open a new tab and go to any path it always redirects to /login. If I remove the bottom switch (with no path - the default), it works as expected. If I navigate to any path having already loaded the react app (i.e. from /login), it works as expected.
Why is the switch not detecting the right path apparently only on first load when the nomatch is included?
Edit: for clarity this is using hashRouter on localhost, react-router-dom v5.2
<Switch>
<div className="loginForm align-middle">
<img src="./img/logo.svg" alt="Restocker logo" className="w-100 p-3 mb-4"/>
<Route path="/verify">
<Verify/>
</Route>
<Route path="/reVerify">
<ReVerify/>
</Route>
<Route path="/register">
<Register/>
</Route>
<Route path="/forgotPassword">
<ForgotPassword/>
</Route>
<Route path="/resetPassword">
<Verify type={"password"}/>
</Route>
<Route path="/login">
<Login/>
</Route>
<Route> //same result using path="*"
//no match - default to login
<Redirect to="/login"/>
</Route>
</div>
</Switch>
Similar topics don't seem to apply to this scenario - either refer to not matching at all (mine does once loaded) or are from much older (2015) versions.
It's important to note that the current version of react-router-dom v6 doesn't support the <switch> component instead it uses the <BrowserRouter> which I like to import as <Router>
import {
BrowserRouter as Router,
Route,
Routes,
} from "react-router-dom";
Also, the v6 uses the <element> component to call the component you wish to run on a particular route.
<Router>
<Navbar/>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<AboutPage />} />
<Route path="contact" element={<ContactPage />} />
</Routes>
</Router>
which means you will have to import those components as well.
import Navbar from "./components/NavBar";
import Home from "./pages";
import AboutPage from "./pages/aboutPage";
import ContactPage from "./pages/contactPage";
I've included a Navbar component and placed it outside inside the <Router> but outside the <Routes> in order for the nav to appear on all routes. But that's more of a design choice.
You might also run into a problem where your route will open and page at the same area on the screen where you were when clicked on the route. Let me know if you'll need help with that. You might not need it if you're app is no longer than the full page length
I thought it would be something silly - the containing div should be outside the switch. It now works as expected (I also changed to using component props instead of children, but both seem to work once the div has been moved).
Working code:
<div className="loginForm align-middle">
<img src="./img/logo.svg" alt="Restocker logo" className="w-100 p-3 mb-4"/>
<Switch>
<Route path="/verify" component={Verify}/>
<Route path="/reVerify" component={ReVerify}/>
<Route path="/register" component={Register}/>
<Route path="/forgotPassword" component={ForgotPassword}/>
<Route path="/resetPassword" render={() => Verify("password")}/>
<Route path="/login" component={Login}/>
<Redirect to="/login"/>
</Switch>
</div>
Note that now all direct children of Switch are now only Route
Edit tweaked based on advice of Drew Reese
I am designing a users dashboard in React, wherein User logs in and navigate to his dashboard with other links such as Archived, Profile and Settings. My Login and then Navigating to HomePage is working fine.
I have designed the Dashboard, Archived, Profile and Settings Page Links in Sidebar. Now when I am navigating to the Links. It takes me to a new URL path and my Sidebar disappears. I want my sidebar to still appear on all pages as long as I am logged in.
Below is my App.js where I have designed the upper level route:
return (
<div>
<Router history={history}>
<Switch>
<PrivateRoute exact path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
<Redirect from="*" to="/" />
</Switch>
</Router>
</div>
);
Once User is on HomePage, I need the dashboard and other links to show. and when User clicks on any Sidebar link, Sidebar should still be there while the other page opens. So I added the inner Routes to the HomePage.jsx like this:
return (
<div>
<Router history={history}>
<Sidebar />
<Switch>
<Route path="/" component={Dashboard} />
<Route path="/archived" component={ArchivedPage} />
<Route path="/profile" component={ProfilePage} />
<Route path="/settings" component={SettingsPage} />
{/* <Redirect from="*" to="/" /> */}
</Switch>
</Router>
</div>
);
But it doesn't work. Can anyone please help me understanding if this is correct. or how can I achieve the required result.
Please let me know if you need any other details.
Thank you.
Issue
The issue is that you are exactly matching "/" to render HomePage, but then as soon as the path is any deeper, like "/archived", it no longer exactly matches and HomePage is unmounted.
You should not render a Router within another Router, you need only one router per app to provide the routing context.
Solution
Remove the inner router (and any other nested routers!!). Remove the exact prop on the "/" path and reorder the routes to specify the more specific paths before less specific paths so the Switch can actually do its job and match and render the appropriate route.
App
Reorder the more specific "/login" and "/register" paths to be matched prior to the less specific "/" path. If you had, for example, a "/login/google" path, this is more specific than "/login" and would be ordered earlier.
return (
<div>
<Router history={history}>
<Switch>
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
<PrivateRoute path="/" component={HomePage} />
<Redirect to="/" />
</Switch>
</Router>
</div>
);
HomePage
Move the Dashboard to the last route position so if no other route above it is matched and returned then the dashboard is matched and rendered.
return (
<div>
<Sidebar />
<Switch>
<Route path="/archived" component={ArchivedPage} />
<Route path="/profile" component={ProfilePage} />
<Route path="/settings" component={SettingsPage} />
<Route component={Dashboard} />
</Switch>
</div>
);
in first place your doing something wrong you cant put a Router inside a Router,
you haver a Router in app then inside a component that is inside of app you have another Router thats a problem i dont know if that solves your problem but try it just delete Router in homepage
so this is my code
<Router>
<Route path="/" component={Nav}/>
<Route path="/" exact component={Home}/>
<Route path="/updates" exact component={Updates} />
<Route path="/author" exact component={Author} />
<Route path="/" component={Footer}/>
</Router>
It works completely fine i just have a slight problem with it. If i were to go to lets say Author page i can just type /author and it will show not only the author but the navbar and footer because i didn't make them exact on purpose but the problem is if i were to make a random link such as ./ejfjife it will still show the navbar and footer i want to make it so if the user made up a link that doesn't exist it'll redirect them to some kind of 'this page doesn't exist' error
thank you
If you always want your Nav and Footer to be present, they shouldn't even be listed under a Route. They can exist outside your Router. Then your Home component can take a path="/" exact and any other route can take the path="/" Component={Error404}. Like this:
<App>
<Nav />
<Router>
<Route path="/" exact component={Home}/>
<Route path="/updates" exact component={Updates} />
<Route path="/author" exact component={Author} />
<Route path="/" component={Error404}/>
</Router>
<Footer />
</App>
My root component is shown below:
ReactDOM.render(
<Provider store={store}>
<Router>
<Menu />
<Switch>
<Route path='/'>
<Home />
</Route>
<Route path='/about'>
<About />
</Route>
</Switch>
</Router>
</Provider>,
document.getElementById('root')
)
and then my Menu component is shown below:
function Menu() {
return (
<ul className='menu'>
<li className='menu-item'>
<Link to='/'>Home</Link>
</li>
<li className='menu-item'>
<Link to='/about'>About</Link>
</li>
</ul>
)
}
export default withRouter(Menu)
The problem is that when I click the relevant link, my About component does not render but the url shows up in the url bar. I am not sure what's wrong and I have gone through all of the questions related to this topic and none of their suggestions have helped me. I am using redux but I do not think that is what is causing the problem. Please help!
As mentioned, the exact prop should be added to the route that renders the Home component:
<Router>
...
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
...
</Router>
The reason for that is to restrict rendering of the Home component to an exact match of "/". Without the exact prop, the Home component will also be rendered for other partially matched routes (ie "/about", which would be considered a partial match).
Some other suggestions; you might consider assigning the component rendered for a route via the component prop on the Route component by doing this:
<Route exact path="/" component={Home} />
Additionally, you can avoid wrapping the Menu component with the withRouter.
For a working example, see this link - hope these pointers help! :)
add exactto your rout, like this
<Route exact path='/'>
<Home />
</Route>
<Route exact path='/about'>
<About />
</Route>
Use the Router logic like this.
<Provider store={store}>
<Router>
<Menu />
<Switch>
<Route path='/' exact component = {Home}/>
<Route path='/about' exact component = {About}/>
</Switch>
</Router>
</Provider>,
I have 2 level of route, the first layer it look like this
<BrowserRouter>
<div>
<AuthRoute></AuthRoute>
<Switch>
<Route path='/dashboard' component={Dashboard} />
</Switch>
</div>
</BrowserRouter>
where in AuthRoute I have a redirect upon componentDidMount
this.props.history.replace(/dashboard/redirected)
The problem is within the dashboard/index which is my 2nd level of route config
<BrowserRouter>
<Switch>
<Route exact path='/dashboard' component={()=><h1>dashboard index</h1>} />
<Route exact path='/dashboard/somewhere' component={()=><h1>somewhere</h1>} />
<Route exact path='/dashboard/redirected' component={() => <h1>redirected</h1>} />
</Switch>
</BrowserRouter>
The route changed to /dashboard/redirect but the component didn't render the correct one if you refresh on says /dashboard/somewhere or /dashboard/
You can see the problem clearer in the demo I setup https://codesandbox.io/s/v0v4qok38l
You only need one <BrowserRouter> in the application - removing it from dashboard/index.js will fix your issue.