I\'d like to render some of my routes within my public layout, and some other routes within my private layout, is there a clean way to do this?
Example that obviousl
UPDATE 2020
Well for now I'm following this approach, it's simpler that the one I posted before:
const Pages = () => {
return (
<ReactRouter>
<Switch>
<Route path="/comingsoon" component={ComingSoon} exact />
<Route>
<MainLayout>
<Switch>
<Route path="/home" exact>
<Home />
</Route>
<Route path="/login" exact>
<Login />
</Route>
<Route path="/useraccount" exact>
<UserAccount />
</Route>
<Route path="/createaccount" exact>
<CreateAccount />
</Route>
<Route path="/contact" exact>
<Contact />
</Route>
<Route path="/about" exact>
<About />
</Route>
<Redirect path="/" exact to="/comingsoon" />
<Route path="*" exact component={NotFound} />
</Switch>
</MainLayout>
</Route>
</Switch>
</ReactRouter>
);
};
In this way, the MainLayout will take care of everything except for the coming soon page.
OLD ANSWER
If you are using Typescript and want to follow this react layout aproach then you can declare your layout like this:
import './Default.less';
import React from 'react';
import { Route } from "react-router-dom";
import { Sider } from './Components';
import { Notification } from 'Client/Components';
interface IDefaultProps {
component: any
path?: string;
exact?: boolean;
}
const Default: React.SFC<IDefaultProps> = (props) => {
const { component: Component, ...rest } = props;
return <Route {...rest} render={matchProps => (
<div className="defaultLayout">
<Sider />
<div className="defaultLayoutContent">
<Component {...matchProps} />
</div>
<Notification />
</div>
)} />
}
export default Default;
And declare routes like this:
import React from 'react';
import { Route } from 'react-router-dom';
import { DefaultLayout } from 'Client/Layout';
import { Dashboard, Matters, Schedules, Students } from './Containers';
export const routes = <div>
<DefaultLayout exact path="/" component={Dashboard} />
<DefaultLayout path="/matters" component={Matters} />
<DefaultLayout path="/schedules" component={Schedules} />
<DefaultLayout path="/students" component={Students} />
</div>;
This solution will work.
<Router>
<Switch>
<PublicLayout>
<Route exact path="/" component={HomePage} />
<Route exact path="/about" component={AboutPage} />
</PublicLayout>
</Switch>
<Switch>
<PrivateLayout>
<Route exact path="/profile" component={ProfilePage} />
<Route exact path="/dashboard" component={DashboardPage} />
</PrivateLayout>
</Switch>
</Router>
Same idea with @Zaptree
Layout
function PublicLayout(props) {
return (
<Route {...props} />
);
}
function PrivateLayout(props) {
return (
<Route {...props} />
);
}
Routes
<Switch>
<PublicLayout exact path="/" component={HomePage} />
<PrivateLayout path="/profile" component={ProfilePage} />
<Route path="/callback" component={NoLayoutPage} />
</Switch>
Update: I solved it another way, but if forces you to namespace the different parts of your app with /app or /admin for example.
Each of the components UserRoutes, AdminRoutes and PublicRoutes are basically large Switch components with the specific layout at its root.
Here's how it looks:
<Router>
<Switch>
<Route path="/app" render={props => <UserRoutes {...props} />} />
<Route path="/admin" render={props => <AdminRoutes {...props} />} />
<Route path="/" render={props => <PublicRoutes {...props} />} />
</Switch>
</Router>
Old: One solution would be to use the render prop of each Route, but it seems really cumbersome:
<Router>
<Switch>
<Route
path="/"
render={() => <PublicLayout><HomePage /></PublicLayout>}
/>
<Route
path="/about"
render={() => <PublicLayout><AboutPage /></PublicLayout>}
/>
<Route
path="/profile"
render={() => <PrivateLayout><ProfilePage /></PrivateLayout>}
/>
<Route
path="/dashboard"
render={() => <PrivateLayout><DashboardPage /></PrivateLayout>}
/>
</Switch>
</Router>
I don't think layouts belong in the route files.
Keep the route clean, ie:
<Route exact path="/" component="HomePage" />
Then, in the HomePage
component, wrap the rendered content in your layout of choice:
...
render() {
<PublicLayout>
<h1>Home page!</h1>
</PublicLayout>
}
This way the routes remain super clean, plus you have an easy way to display routes which should support both layouts (404 pages for instance).
I am going to write this everywhere where this question was asked so sorry if you've seen it elsewhere. I am only doing it cause I've struggled for a while and I think it's worth spreading this solution as much as possible. Enough words, this is what I did, I think it's pretty self explanatory. Works like a charm and it's very easy to type.
const withLayout = (LayoutComp, ComponentComp) => <LayoutComp><ComponentComp /></LayoutComp>;
const withDefaultLayout = (ComponentComp) => () => withLayout(Layout, ComponentComp);
const withEmptyLayout = (ComponentComp) => () => withLayout(EmptyLayout, ComponentComp);
export const routes = <div>
<Switch>
<Route path="/" exact render={withDefaultLayout(Home)} />
<Route path='/subscriptions' render={withDefaultLayout(SubscriptionsWrapped)} />
<Route path='/callback' render={withEmptyLayout(AuthCallback)} />
<Route path='/welcome/initial' render={withEmptyLayout(Start)} />
</Switch>
</div>;