Separate the memory router and browser router in react application - javascript

I have created a react application with a home page and survey containing 15 questions on 15 pages.
I used a BrowserRouter to wrap the home page in the '/' route. I listed the 15 pages under the MemoryRouter to make it display under the '/apply' route. The issue here is the initial entry is visible in the '/' route. MemoryRouter should not be visible in the '/' route. It should be there on the '/apply' path alone.
import React from "react";
import BusinessType from "./BusinessType";
import {
BrowserRouter as Router,
MemoryRouter,
Routes,
Route
} from "react-router-dom";
import Howmuch from "./Howmuch";
import Seeking from "./Seeking";
import Date from "./Date";
import AnnualRevenue from "./Annualrevenue";
import Creditscore from "./Creditscore";
import BusinessName from "./BusinessName";
import Industry from "./Industry";
import Deposit from "./Deposit";
import Zipcode from "./Zipcode";
import Name from "./Name";
import Phone from "./Phone";
import Email from "./Email";
import Home from "./Pages/Home";
import Require from "./Require";
import Apply from "./Apply";
function App() {
return(
<div>
<Router>
<div>
<Routes>
<Route exact path='/' element={<Home />} />
</Routes>
</div>
</Router>
<MemoryRouter initialEntries={['/apply']} initialIndex={0}>
<Routes>
<Route path='/apply' element={<BusinessType />} />
<Route path='/Qn2' element={<Howmuch />} />
<Route path='/Qn3' element={<Seeking />} />
<Route path='/Qn4' element={<Date />} />
<Route path='/Qn5' element={<AnnualRevenue />} />
<Route path='/Qn6' element={<Creditscore />} />
<Route path='/Qn7' element={<BusinessName />} />
<Route path='/Qn8' element={<Industry />} />
<Route path='/Qn9' element={<Deposit />} />
<Route path='/Qn10' element={<Zipcode />} />
<Route path='/Qn11' element={<Name />} />
<Route path='/Qn12' element={<Phone />} />
<Route path='/Qn13' element={<Email />} />
<Route path='/final' element={<Require />} />
<Route path='/congrats' element={<Apply />} />
</Routes>
</MemoryRouter>
</div>
);
}
export default App;

If I'm understanding your post and comments correctly it seems you are saying that the BusinessType component is being rendered even though the current URL path is "/". The issue here is that the MemoryRouter path matching isn't coupled to the browser's address bar and you've initialized to "/apply" and so that is the "path" that is matched and rendered regardless what the URL is in the browser's address bar.
I used two separate routers because all pages of the survey should be
under the '/apply' route.
In this case I'd suggest rendering all these routes in the main BrowserRouter under the appropriate route paths.
Example:
import React from "react";
import BusinessType from "./BusinessType";
import {
BrowserRouter as Router,
Routes,
Route
} from "react-router-dom";
...
function App() {
return(
<div>
<Router>
<div>
<Routes>
<Route path='/' element={<Home />} />
<Route path="/apply">
<Route index element={<BusinessType />} /> // "/apply"
<Route path='/Qn2' element={<Howmuch />} /> // "/apply/qn2"
<Route path='/Qn3' element={<Seeking />} /> // "/apply/qn3"
<Route path='/Qn4' element={<Date />} /> // "/apply/qn4"
...
<Route path='/Qn12' element={<Phone />} /> // "/apply/qn12
<Route path='/Qn13' element={<Email />} /> // "/apply/qn13
<Route path='/final' element={<Require />} /> // "/apply/final"
<Route path='/congrats' element={<Apply />} /> // "/apply/congrats"
</Route>
</Routes>
</div>
</Router>
</div>
);
}
export default App;

Related

Blank display when I use link Routes in React

If I search "http://localhost:3000/" or "http://localhost:3000/login", my display is completely blank.
app.js
import React from 'react'
import Login from './pages/login'
import Home from './pages/home'
import Error from './pages/error'
import { Link, Router, Route, Routes } from 'react-router-dom';
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="*" element={<Error />} />
</Routes>
)
}
export default App;
home.js
import React from "react";
const Home = () => {
return <h1>The Home</h1>;
};
export default Home;
Refactor to look like:
import { Route, Routes, BrowserRouter } from 'react-router-dom';
// ...
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="*" element={<Error />} />
</Routes>
</BrowserRouter>
);
};

React routing based on id

I work with react-router v6. I want to create a new route based on an id. On my homepage "example.com" I have a selection of articles. I want to create a detail view for each article "example.com/{id}". My approach looks like this:
App.tsx
import {
BrowserRouter,
Routes,
Route,
} from "react-router-dom";
import ProjectWrapper from "./components/ProjectWrapper";
import Home from "./pages/Home";
import PageError from "./pages/PageError";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} >
<Route path=":id" element={<ProjectWrapper />} />
</Route>
<Route path="*" element={<PageError />} />
</Routes>
</BrowserRouter>
);
}
ProjectWrapper.tsx
import { useParams } from "react-router-dom";
import { ProjectList } from "../pages/algorithms/ProjectList";
import PageError from "../pages/PageError";
function ProjectWrapper() {
const { id } = useParams();
const project = ProjectList.find((project) => project.id.toLowerCase() === id?.toLowerCase());
if (project === undefined) return (<PageError />);
return (
<div>
{project!.shortDescription}
</div>
)
}
export default ProjectWrapper;
Am I missing something ?
With the given routing code:
<Routes>
<Route path="/" element={<Home />} >
<Route path=":id" element={<ProjectWrapper />} />
</Route>
<Route path="*" element={<PageError />} />
</Routes>
Home is what is called a Layout Route. Layout routes render some common logic and UI, and an Outlet component for nested Routes to render their content when matched.
Example:
import { ..., Outlet } from 'react-router-dom';
const Home = () => {
...
return (
<>
...
<Outlet /> // <-- nested routes render content here
</>
);
};
If you don't want the Home component to render along with children routes then place it on its own route.
Examples:
<Routes>
<Route path="/" element={<Home />} />
<Route path="/:id" element={<ProjectWrapper />} />
<Route path="*" element={<PageError />} />
</Routes>
or
<Routes>
<Route path="/">
<Route index element={<Home />} />
<Route path=":id" element={<ProjectWrapper />} />
</Route>
<Route path="*" element={<PageError />} />
</Routes>

React Router v6 always render "/"

I'm trying to implement router in react-create-app but it always render "/" and showing Home or SignIn page. How can I solve this?
function AppRouter({ isLoggedIn, user }) {
return(
<Router>
<Routes>
<Route path="/profile" element={<Profile />} />
<Route path="/signUp" element={<SignUp />} />
{isLoggedIn
? <Route exact path={"/"} element={<Home user={user}/>} />
: <Route exact path={"/"} element={<SignIn />} />
}
</Routes>
</Router>
)
}
It seems you have a slight misunderstanding of how the HashRouter works with the UI.
import { HashRouter as Router, Route, Routes } from "react-router-dom";
import Profile from "./Profile";
import SignUp from "./SignUp";
import Home from "./Home";
export default function App() {
return (
<Router>
<Routes>
<Route path="/profile" element={<Profile />} />
<Route path="/signUp" element={<SignUp />} />
<Route path="/" element={<Home />} />
</Routes>
</Router>
);
}
The HashRouter handles routing with a URL hash value, i.e. everything after the "#" in the URL. If you are trying to render your app and access "<domain>/" instead of "<domain>/#/" the routing won't work.
For example in your running codesandbox demo, the base URL is "https://5p7hff.csb.app/". At this base URL the hash router isn't really working, and you should really be accessing "https://5p7hff.csb.app/#/" instead so the hash router is loaded and the app's internal routing can work.
From "https://5p7hff.csb.app/#/" you should be to then navigate to any of your routes, i.e. "https://5p7hff.csb.app/#/profile" and https://5p7hff.csb.app/#/signUp".
If you switch to a different router, like the BrowserRouter then the "/#/" is no longer used, the router and routes render from "/" where the app is running from. The routes would be "https://5p7hff.csb.app/", "https://5p7hff.csb.app/profile", and "https://5p7hff.csb.app/signUp".

React Router, hide Nav & footer on certain pages. with Router V6

So i have tried for quiet some time to hide the nav and footer components in certain pages of the site, but sadly no luck. I've tried multiple solutions on Stackoverflow, only one of them worked partially by creating a new Layout component and then putting that inside the Routes to then exclude the footer and nav from for example the login page. But the issue was that it worked, but on homepage it then only showed the footer and nav, and nothing in between like the design I made in the homepage.
The only solution that works for me is by creating the and like I did in the example, but then I cant exclude certain pages and hide them there...
This is how it looks currently and not working:
import React from "react";
import Home from ".//Pages/Home";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Dashboard from "./Pages/Dashboard";
import Login from "./Pages/Login";
import Price from "./Pages/Price";
import ErrorPage from "./Pages/ErrorPage";
import Navbar from "./components/Navbar";
import Footer from "./components/Footer";
import Profile from "./Pages/Profile";
function App() {
return (
<Router>
<nav>
<Navbar />
</nav>
<Routes>
<Route index element={<Home />} />
<Route path="/Dashboard" element={<Dashboard />} />
<Route path="/Login" element={<Login />} />
<Route path="/Price" element={<Price />} />
<Route path="/Profile/:username" element={<Profile />} />
<Route path="/*" element={<ErrorPage />} />
</Routes>
<footer>
<Footer />
</footer>
</Router>
);
}
export default App;
Hi you can do it by having a state that only when the state is true the nav and footer will render:
function App() {
const [showNav, setShowNav- = useState(true);
return (
<Router>
{ showNav &&
<nav>
<Navbar />
</nav>
}
<Routes>
<Route index element={<Home />} />
<Route path="/Dashboard" element={<Dashboard />} />
<Route path="/Login" element={<Login />} />
<Route path="/Price" element={<Price />} />
<Route path="/Profile/:username" element={<Profile />} />
<Route path="/*" element={<ErrorPage />} />
</Routes>
{showNav &&
<footer>
<Footer />
</footer>
</Router>
}
);
}
And for example, if you don't want to show the nav in the homepage you will pass the setShowNav function as a prop and will set it to false:
<Route index element={<Home funcNav={setShowNav}/>} />
in home page:
props.funcNav(false);
You can use modularization in your app segmenting it into different sections. This can best be accomplished by using nested routes in your app each. For example you could have example.com/routes/xxx have one layout and have example.com/other/xxx have another layout... You could also use this to optionally render the navbar and footer as you have mentioned.It is a good idea to segment your app if it has very different features/areas where different navbar/footer combinations need to be used. Here is an example using most of your code which would segment it into a main layout, and no layout.
App.js
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import PageWithoutHeaderOrFooter from "./Pages/NoHeaderOrFooter";
import MainLayoutRoutes from "./Layouts/MainLayoutRoutes";
function App() {
return (
<Router>
<Routes>
<Route path="/noheaderorfooter" element={<PageWithoutHeaderOrFooter />} />
<Route path="*" element={<MainLayoutRoutes />} />
</Routes>
</Router>
);
}
export default App;
MainLayuotRoutes.js
import React from 'react';
import Home from ".//Pages/Home";
import Dashboard from "./Pages/Dashboard";
import Login from "./Pages/Login";
import Price from "./Pages/Price";
import ErrorPage from "./Pages/ErrorPage";
import Navbar from "./components/Navbar";
import Footer from "./components/Footer";
import Profile from "./Pages/Profile";
function MainLayoutRoutes() {
return (
<React.Fragment />
<nav>
<Navbar />
</nav>{/*This is outside the routes component on purpose read below*/}
<Routes>
<Route index element={<Home />} />
<Route path="/Dashboard" element={<Dashboard />} />
<Route path="/Login" element={<Login />} />
<Route path="/Price" element={<Price />} />
<Route path="/Profile/:username" element={<Profile />} />
<Route path="/*" element={<ErrorPage />} />
</Routes>
<footer>
<Footer />
</footer>
<React.Fragment />
)
}
export default MainLayoutRoutes;
A couple things I would like to note about this code.
First each child component in a Routes component must be a Route component (this doesn't include the element part of the Route component). This is why I am using a React.Fragment (you could have just as easily used <></>) if you didn't want an additional div rendered.
Secondly using this type of routing is good for segmenting your app into areas... Using areas not only is better for routing it is also better for SEO (where applicable as some crawlers don't yet support JavaScript).
Lastly I would like to mention if there is a rare case where there is only 1 page that you want a different navbar or footer, just use conditional rendering to take care of the edge case.
You can also use UseLocation from react-router-dom
const { pathname } = useLocation();
<footer>
{pathname !== '/<SOME_ROUTE>' &&
<Footer />}
</footer>
yes you should apply condition that will check if current location will display nav or not
You should use useLocation from react-router
To do this
Here is example from official documentation how you can do that.
Using Route components:
<Routes>
<Route path="/" element={<App />}>
<Route index element={<Home />} />
<Route path="teams" element={<Teams />}>
<Route path=":teamId" element={<Team />} />
<Route path=":teamId/edit" element={<EditTeam />} />
<Route path="new" element={<NewTeamForm />} />
<Route index element={<LeagueStandings />} />
</Route>
</Route>
<Route element={<PageLayout />}>
<Route path="/privacy" element={<Privacy />} />
<Route path="/tos" element={<Tos />} />
</Route>
<Route path="contact-us" element={<Contact />} />
</Routes>
Using useRoutes hook:
let routes = [
{
element: <App />,
path: "/",
children: [
{
index: true,
element: <Home />,
},
{
path: "teams",
element: <Teams />,
children: [
{
index: true,
element: <LeagueStandings />,
},
{
path: ":teamId",
element: <Team />,
},
{
path: ":teamId/edit",
element: <EditTeam />,
},
{
path: "new",
element: <NewTeamForm />,
},
],
},
],
},
{
element: <PageLayout />,
children: [
{
element: <Privacy />,
path: "/privacy",
},
{
element: <Tos />,
path: "/tos",
},
],
},
{
element: <Contact />,
path: "/contact-us",
},
];
And of course you should use <Outlet/> component inside <App /> and <PageLayout /> to render childrens inside those layouts.
App.js
<Router>
<Routes>
//your other route
<Route path="/404" element={<NotFound />} />
<Route path="*" element={<Navigate to="/404" />} />
</Routes>
</Router>
Navbar.js
const withouSidebarRoutes = ["404", "/signin", "/etc"];
const { pathname } = useLocation();
if (withouSidebarRoutes.some((item) => pathname.includes(item)))
return null;
Work fine for me :))

How to set a basename for react-router Router

How can I config the basename, or keep a path in url like localhost:8000/app and when I have to redirect to another Route the Router identify this /app as part of url and do not change it, this is my component structure.
import React from 'react';
import { Router, Route, browserHistory, IndexRoute } from 'react-router';
<Router history={browserHistory} >
<Route component={App}>
<Route path="/" component={Home} />
<Route path="/login" component={LoginContainer} />
<Route path="apresentacao">
<IndexRoute component={NameContainer} />
<Route path="2" component={HsContainer} />
<Route path="3" component={McContainer} />
<Route path="4" component={MpvContainer} />
</Route>
</Route>
</Router>
If you are using React Router v4, you can use the basename prop of the Router component to change the base of your app.
import React from "react";
import { Router, Route, browserHistory, IndexRoute } from "react-router";
class App extends React.Component {
render() {
return (
<Router history={browserHistory} basename="/app">
<Route component={App}>
<Route path="/" component={Home} />
<Route path="/login" component={LoginContainer} />
<Route path="apresentacao">
<IndexRoute component={NameContainer} />
<Route path="2" component={HsContainer} />
<Route path="3" component={McContainer} />
<Route path="4" component={MpvContainer} />
</Route>
</Route>
</Router>
);
}
}
If you are using React Router v3, you need to install the history package separately and use the useBasename function.
import React from "react";
import { Router, Route, browserHistory, IndexRoute } from "react-router";
import { useBasename } from 'history'
class App extends React.Component {
render() {
return (
<Router history={useBasename(() => browserHistory)({ basename: '/app' })}>
<Route component={App}>
<Route path="/" component={Home} />
<Route path="/login" component={LoginContainer} />
<Route path="apresentacao">
<IndexRoute component={NameContainer} />
<Route path="2" component={HsContainer} />
<Route path="3" component={McContainer} />
<Route path="4" component={MpvContainer} />
</Route>
</Route>
</Router>
);
}
}

Categories

Resources