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

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 :))

Related

Separate the memory router and browser router in react application

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;

Changing from v5 to v6, how to make it work with relative paths?

My application has scenarios where we need several routes to "pass" through a component to only then render the specifics, not only that but also situations where something is shown for the "parent" route and then split for the children...
It is imperative to note that we don't have a single "route config" file, and instead our routes are where we need them.
This was possible with v5, but I am very confused about how to get this accomplished with the new version.
So, currently we have stuff such as:
App.js
function App = () => {
return (
<Switch>
<Route exact path={['/', '/2', '/more-info']} component={Login} />
<Route path="/(main|settings|notifications)" component={AuthenticatedUser} />
<Redirect from="*" to="/404" />
</Switch>
);
}
AuthenticatedUser.js
function AuthenticatedUser= () => {
{... lots of common code}
return (
<div>
{...common html}
<Switch>
<Route exact path="/main" component={Main} />
<Route path="/settings" component={Settings} />
<Route path="/notifications" component={Notifications} />
</Switch>
</div>
);
}
Settings.js
function Settings= () => {
{... lots of common code}
return (
<div>
{...common html}
<Switch>
<Route exact path="/settings/basic" component={Basic} />
<Route exact path="/settings/notifications" component={Notifications} />
</Switch>
</div>
);
}
Now, with the relative from the parent, I am not able to get the same structure, I am also confused about how to get the routes split into separate files not even talking about the regex situation that I am guessing the solution is to duplicate the lines as many times as I have items in that regex...
You have basically 2 options when it comes to declaring the routes and sharing common UI:
Use layout routes and nested Route components.
Render routed components that render descendent routes in another Routes component wrapping descendent Route components.
Using layout and nested routes
Convert AuthenticatedUser into a layout route. Layout routes render an Outlet for nested routes to render their matched element into.
import { Outlet } from 'react-router-dom';
function AuthenticatedUser = () => {
{... lots of common code}
return (
<div>
{...common html}
<Outlet />
</div>
);
};
Convert Settings also into a layout route component.
import { Outlet } from 'react-router-dom';
function Settings = () => {
{... lots of common code}
return (
<div>
{...common html}
<Outlet />
</div>
);
};
App
import { Routes, Route, Navigate } from 'react-router-dom';
function App = () => {
return (
<Routes>
<Route path="/" element={<Login />} />
<Route path="/2" element={<Login />} />
<Route path="/more-info" element={<Login />} />
<Route element={<AuthenticatedUser />}>
<Route path="/main" element={<Main />} />
<Route path="/settings" element={<Settings />}>
<Route
path="basic" // "/settings/basic"
element={<Basic />}
/>
<Route
path="notifications" // "/settings/notifications"
element={<Notifications />}
/>
</Route>
<Route path="/notifications" element={<Notifications />} />
</Route>
<Route path="*" element={<Navigate to="/404" replace />} />
</Routes>
);
};
Using descendent routes
Here the parent routes need to render their route path with a trailing "*" wildcard matcher so descendent routes can also be matched. Descendent Routes components build their route paths relative to their parent Route path. I'd still suggest using AuthenticatedUser as a layout route for ease, otherwise you'll have a lot of code duplication since you'd need to wrap each route individually.
App
import { Routes, Route, Navigate } from 'react-router-dom';
function App = () => {
return (
<Routes>
<Route path="/" element={<Login />} />
<Route path="/2" element={<Login />} />
<Route path="/more-info" element={<Login />} />
<Route element={<AuthenticatedUser />}>
<Route path="/main" element={<Main />} />
<Route path="/settings/*" element={<Settings />} />
<Route path="/notifications" element={<Notifications />} />
</Route>
<Route path="*" element={<Navigate to="/404" replace />} />
</Routes>
);
};
Settings
import { Routes } from 'react-router-dom';
function Settings = () => {
{... lots of common code}
return (
<div>
{...common html}
<Routes>
<Route
path="/basic" // "/settings/basic"
element={<Basic />}
/>
<Route
path="/notifications" // "/settings/notifications"
element={<Notifications />}
/>
</Routes>
</div>
);
};

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>

How to skip header and footer for certain routes in ReactJS?

I have the following code which renders an app with a header and footer for all pages.
app.js
import React from 'react';
import {
Route,
Switch
} from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router'
import Layout from './components/Layout'
import Home from './homeComponent';
import Login from './loginComponent';
import Dashboard from './dashboardComponent';
const App = ({ history }) => {
return (
<Layout>
<ConnectedRouter history={history}>
<Switch>
<Route exact={true} path="/" component={Home} />
<Route path="/login" component={Login} />
<Route path="/dashboard" component={Dashboard} />
... more routes
<Route component={NoMatch} />
</Switch>
</ConnectedRouter>
</Layout>
);
};
export default App;
layout.js
import Header from './headerComponent'
import Footer from './footerComponent'
import React, {Component} from 'react'
class Layout extends Component {
render() {
return (
<div>
<Header />
{this.props.children}
<Footer />
</div>
)
}
}
What is the best way to skip rendering of the header and footer for certain pages like Home and Login routes?
I'd recommend creating two layouts with their own header and footers and a private route:
Public Layout
export const PublicLayout = (props) => <div>
<PublicHeader/>
<Switch>
<Route exact path="/" component={HomePage}/>
<Route exact path='/signin' component={SigninForm} />
<Route exact path='/signup' component={Signup} />
</Switch>
<PublicFooter/>
Protected Layout
export const ProtectedLayout = (props) => <div>
<ProtectedHeader/>
<Switch>
<PrivateRoute exact path='/app/dashboard' component={Dashboard} />
<Route component={NotFound} />
</Switch>
<ProtectedFooter/>
Define high-level routes in app.js:
export default () => {
return <div>
<Switch>
<Route path='/app' component={ProtectedLayout} />
<Route path='/' component={PublicLayout} />
</Switch>
</div>
}
Define PrivateRoute:
export default ({component: Component, ...rest}) => (
<Route {...rest} render={props => (
window.globalState.isAuthenticated() ? (
<Component {...props} />
) : (
<Redirect to={{
pathname: '/signin',
state: {from: props.location}
}} />
)
)} />
)
Yeah i know a bit late .
Visual studio 2019
import React from 'react';
import { Container } from 'reactstrap';
import NavMenu from '../components/NavMenu';
export default props => (
<div>
{window.location.pathname !== '/login' ? <NavMenu /> : null}
<Container>
{props.children}
</Container>
</div>
);
i hope somebody helps out there.. !!! Happy coding
I made some solution while solving the problem.
First You can wrap the Switch in a website header and footer
<BrowserRouter>
<WebsiteHeader />
<Switch>
<Route/>
<Route/>
<Route/>
</Switch>
<WebsiteFooter/>
<BrowserRouter>
then inside the header or footer wrap the components using withRouter from 'react-router-dom' so you can access the routes props
const WebsiteHeader = props => {
if (props.location.pathname == "/register") return null;
return (
<Fragment>
<DesktopHeader {...props} />
<MobileHeader {...props} />
</Fragment>
);
};
export default withRouter(WebsiteHeader);
Use render
<ConnectedRouter history={history}>
<Switch>
<Route path="/dashboard" render={props => <Layout><Dashboard {...props} /></Layout>} />
<Route path="/login" component={Login} />
</Switch>
</ConnectedRouter>
For forcefully refresh Header inside routing.
use forceRefresh={true}
const Routing = () => {
return(
<BrowserRouter forceRefresh={true}>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list/:id" component={ListingApi}/>
<Route path="/details/:id" component={HotelDetails}/>
<Route path="/booking/:hotel_name" component={PlaceBooking}/>
<Route path="/viewBooking" component={ViewBooking}/>
<Route exact path="/login" component={LoginComponent}/>
<Route path="/signup" component={RegisterComponent}/>
</Switch>
<Footer/>
</BrowserRouter>
)
}
I would just create a few different layouts one with header and footer and one without. And then instead of wrapping everything into one layout. I'd just do this wrapping inside each page component. So your components would be like:
Dashboard component
<SimpleLayout>
<Dashboard>
</SimpleLayout>
Home component
<MainLayout>
<Home>
</MainLayout>
Try like this
<Route path="/" render={(props) => (props.location.pathname !== "/login") &&
<Header />}>
</Route>
<Route path="/" render={(props) => (props.location.pathname !== "/login") &&
<Menu />}>
</Route>
<PrivateRoute path="/scope" component={Scope} ></PrivateRoute>
<Route exact path="/login" component={Login} />
In this example I'm checking the URL, If the URL is "/Login" I'm removing Menu and header component
For forcefully refresh Header inside routing.
const Routing = () => {
return(
<BrowserRouter forceRefresh={true}>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list/:id" component={ListingApi}/>
<Route path="/details/:id" component={HotelDetails}/>
<Route path="/booking/:hotel_name" component={PlaceBooking}/>
<Route path="/viewBooking" component={ViewBooking}/>
<Route exact path="/login" component={LoginComponent}/>
<Route path="/signup" component={RegisterComponent}/>
</Switch>
<Footer/>
</BrowserRouter>
)
}

Using multiple layouts for react-router components

If I have the following:
<Route path="/" component={Containers.App}>
{ /* Routes that use layout 1 */ }
<IndexRoute component={Containers.Home}/>
<Route path="about" component={Containers.About}/>
<Route path="faq" component={Containers.Faq}/>
<Route path="etc" component={Containers.Etc}/>
{ /* Routes that use layout 2 */ }
<Route path="products" component={Containers.Products}/>
<Route path="gallery" component={Containers.Gallery}/>
</Route>
How can I make it so that the two sets of routes each use a different layout.
If I only had a single layout then I would put it in App, but in this case where do I define the layout?
To make it even more complicated some of the layout components (eg top nav) are shared between both layout types.
You can use routes without a path to define containers that are not defined by the url:
<Route path="/" component={Containers.App}>
{ /* Routes that use layout 1 */ }
<Route component={Containers.Layout1}>
<IndexRoute component={Containers.Home}/>
<Route path="about" component={Containers.About}/>
<Route path="faq" component={Containers.Faq}/>
<Route path="etc" component={Containers.Etc}/>
</Route>
<Route component={Containers.Layout2}>
{ /* Routes that use layout 2 */ }
<Route path="products" component={Containers.Products}/>
<Route path="gallery" component={Containers.Gallery}/>
</Route>
</Route>
The layout components can then import additional components such as the top nav
Route's path property has accepted an array of strings for a while now. See https://github.com/ReactTraining/react-router/pull/5889/commits/4b79b968389a5bda6141ac83c7118fba9c25ff05
Simplified to match the question routes, but I have working multiple layouts essentially like this (using react-router 5):
<App>
<Switch>
<Route path={["/products", "/gallery"]}>
<LayoutTwo>
<Switch>
<Route path="/products" component={Products} />
<Route path="/gallery" component={Gallery} />
</Switch>
</LayoutTwo>
</Route>
{/* Layout 1 is last because it is used for the root "/" and will be greedy */}
<Route path={["/about", "/faq", "/etc", "/"]}>
<LayoutOne>
<Switch>
<IndexRoute component={Home} />
<Route path="/about" component={About} />
<Route path="/faq" component={Faq} />
<Route path="/etc" component={Etc} />
</Switch>
</LayoutOne>
</Route>
</Switch>
</App>
This solution prevents re-mounting the layouts on route changes, which can break transitions, etc.
Here's a great way to use multiple layouts with different React components.
In your router you can use:
<Router history={browserHistory}>
<Route component={MainLayout}>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</Route>
<Route component={EmptyLayout}>
<Route path="/sign-in" component={SignIn} />
</Route>
<Route path="*" component={NotFound}/>
</Router>
Source: https://sergiotapia.me/different-layouts-with-react-router-71c553dbe01d
Pintouch, I was able to get this working with the following example:
Layout1:
import React from 'react'
const Layout1 = (props) => (
<div>
<h1>Layout 1</h1>
{props.children}
</div>
)
export default Layout1
Layout2:
import React from 'react'
const Layout2 = (props) => (
<div>
<h1>Layout 2</h1>
{props.children}
</div>
)
export default Layout2
Layout Container:
import React from 'react'
const LayoutContainer = (props) => (
<div>
{props.children}
</div>
)
export default LayoutContainer
Routes:
import React from 'react';
import { Router, Route, IndexRoute, hashHistory } from 'react-router';
import LayoutContainer from './LayoutContainer'
import Layout1 from './Layout1'
import Layout2 from './Layout2'
import ContactManagerView from './ContactManagerView'
import CallerIdView from './CallerIdView'
import NotFound from './NotFound'
<Router history={hashHistory}>
<Route path="/" component={LayoutContainer}>
<Route component={Layout1}>
<IndexRoute component={DashboardView}/>
<Route path='Contacts' component={ContactManagerView}/>
</Route>
<Route component={Layout2}>
<Route path='CallerId' component={CallerIdView}/>
</Route>
<Route component={Layout}>
<Route path='*' component={NotFound}/>
</Route>
</Route>
</Router>
This is how it's done in React Router v6:
<Route path="/" element={<App />}>
{/* Routes that use layout 1 */}
<Route element={<BlueLayout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="faq" element={<Faq />} />
<Route path="etc" element={<Etc />} />
</Route>
{/* Routes that use layout 2 */}
<Route element={<RedLayout />}>
<Route path="products" element={<Products />} />
<Route path="gallery" element={<Gallery />} />
</Route>
</Route>
I've created a complete example in StackBlitz here.
You could create a function RouteWithLayout that renders the <Route> wrapped within the layout:
const RouteWithLayout = ({ component: Component, layout: Layout, ...rest }) => (
<Route {...rest} render={props => (
<Layout>
<Component {...props} />
</Layout>
)} />
)
const MainLayout = props => (
<div>
<h1>Main</h1>
{props.children}
</div>
)
const AltLayout = props => (
<div>
<h1>Alt</h1>
{props.children}
</div>
)
const Foo = () => (
<p>Foo</p>
)
const Bar = () => (
<p>Bar</p>
)
const App = () => (
<div>
<Switch>
<RouteWithLayout exact path="/foo" layout={MainLayout} component={Foo} />
<RouteWithLayout exact path="/bar" layout={AltLayout} component={Bar} />
</Switch>
</div>
)
I came across this question and found a solution that I want to share.
With react router v4 we could render the routes directly in your layout. Which is more readable and easy to maintain.
Layout
export class MainLayout extends React.PureComponent {
render() {
return (
<div>
<Header />
{this.props.children}
<Footer />
</div>
);
}
}
Mainlayout.propTypes = {
children: PropTypes.node.isRequired,
}
Router
export default function App() {
return (
<Switch>
<MainLayout>
<Switch>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</MainLayout>
<OtherLayout>
.... other paths
</OtherLayout>
</Switch>
);
}

Categories

Resources