React router switch doesn't match on first load - javascript

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

Related

How do I make react router v6 load elements without having to manualy refresh the url?

When I send the user to a URL (in this case /login and /signup and then back to /)
the elements on my page don't load automatically by entering the URL, I instead have to manually refresh in order for the content to load.
This is my index.js which handles the routes (with react router v6)
import Navbar from "./components/navbar/navbar";
import Footer from "./components/footer/footer";
import Home from "./pages/home/home";
import Login from "./pages/user/login/login";
import Signup from "./pages/user/signup/signup";
ReactDOM.render(
<div>
<Navbar />
<BrowserRouter>
<Routes>
<Route index path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
</Routes>
</BrowserRouter>
<Footer />
</div>,
document.getElementById("root")
);
This is an example of what happens when I send the user to /login with the use of the Link component that I am importing through React-router.
Before refreshing the URL on /login
I then have to manually reload the page by pressing the reload button, only after doing so the content will load.
After refreshing the URL on /login
the same applies if I try to go back to the homepage using the Link component
Before refreshing on the URL /
I then have to reload in order to remove the login box
After refreshing on the URL /
I reproduced the same behavior. CodeSandbox (try it and look at home.js)
You don't seem to be using the page navigation correctly. The most react way is to use the useNavigation() hook.
If navigation is working but the routes aren't then I suspect you are rendering them into separate routers. I notice you render the Navbar outside your BrowserRouter, and since navigation is working and updating the URL in the address bar is fairly safe to assume those links are correctly wrapped in a router. You'd see an invariant warning/error otherwise.
ReactDOM.render(
<div>
<Navbar /> // <-- must have another router if it is working
<BrowserRouter>
<Routes>
<Route index path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
</Routes>
</BrowserRouter>
<Footer />
</div>,
document.getElementById("root")
);
You should have only one router wrapping the app and providing the routing context to all Routes, Route, Navigate, Link, etc... components.
Remove any extraneous routers in other components, like NavBar, and move them all to be within the BrowserRouter you are rendering here.
ReactDOM.render(
<BrowserRouter>
<Navbar />
<Routes>
<Route index path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
</Routes>
<Footer />
</BrowserRouter>,
document.getElementById("root")
);

How to configure the Routes in Sidebar navigation after Login page in React?

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

How to load first menu item by default with a different Router Link

I have React Router setup in my Reactjs Project. The header Component has 4 different menu items. After login, I am getting only header component rendered but not first menu item component below it.
I have created a Homepage component which loads Header component and below that I gave Routes for different menu item pages. In the Header component for every Item, I linked it to the corresponding Item Page.
//Home Page Code.
<Router>
<Header />
<Route path='/Jobs' component={Jobs} />
<Route path='/Admin' component={Admin} />
<Route path='/Requests' component={Requests} />
</Router>
To use react router you have to wrap your routes in switch.
Switch will render the first item that matches the current route.
Because you have no switch, the routes are ignored.
To render a default site, change the path of the last route to / and it will match everything.
By setting it as last element, it will always be rendered, if no other route above matches the current route.
<Router>
<Header />
<Switch>
<Route path='/Jobs' component={Jobs} />
<Route path='/Admin' component={Admin} />
<Route path='/' component={Requests} />
</Switch>
</Router>
Hope this helps. Happy coding.
Try putting <Switch></Switch> container around your routes:
//Home Page Code.
<Router>
<Header />
<Switch>
<Route exact path='/' component={Home} />
<Route path='/Jobs' component={Jobs} />
<Route path='/Admin' component={Admin} />
<Route path='/Requests' component={Requests} />
</Switch>
</Router>
Edited: to add path for home (path='/')

React hashRouter doesn't render correct component when refreshing

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}/>

react router v4 route changed but did not render the correct component

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.

Categories

Resources