I have a page layout with 3 separate sections: The sidebar, the header and the main body. I would like to fill the main body from the child route, while parent routes define the header or sidebar – but after trying to work with Providers and Context approaches, I couldn’t quite find the right approach.
Here’s a baseline / pseudo-code of what I would like to achieve:
Example Layout:
layout.tsx
export function DefaultLayout() {
return (
<div class="sidebar">
<!-- sidebar content goes here -->
</div>
<div class="page">
<div class="page-header">
<!-- header content goes here -->
</div>
<div class="page-body">
<Outlet />
</div>
</div>
);
}
Example routes:
router
import { Route } from "react-router-dom";
<Route element={<DefaultLayout />}>
<Route
path="/dashboard"
sidebar={<DefaultSidebar />}
header={<DashboardHeader />}
>
<Route path="home" element={<DashboardHomePage />}>
<Route path="stats" element={<DashboardStatsPage />}>
<Route path="help" element={<DashboardHelpPage />}>
</Route>
<Route path="/user" sidebar={<UserSidebar />} header={<UserHeader />}>
<Route path="overview" element={<UserOverviewPage />}>
<Route path="accounts" element={<UserAccountsPage />}>
</Route>
</Route>
As seen in the simplified example above, I would like to define the overall Layout in a parent route, while "filling" the layout sections in nested routes. sidebar={}
and header={}
are just pseudo-code for the example, I realize that it’s probably part of another element={}
wrapper.
I’ve tried solving this by creating a <SidebarProvider>
and <HeaderProvider>
component, working with things like useOutletContext
and passing the state downwards, but that didn’t seem to work and was quickly getting hopelessly complicated (infinite loops, etc).
So, starting fresh: what would be a method to achieve the above behavior? If it’s via providers, how should I structure them?
2
Answers
If I understood correctly you want to render dynamically only one part of the app. In that case you can directly embed the routes inside your "dynamic" section.
In you case your Layout component would become:
I made also a demo of what It’d look like https://codesandbox.io/s/naughty-lalande-j3378g?file=/src/App.js:318-322.
I would suggest adding the
header
andsidebar
as props to theDefaultLayout
route component and render them accordingly. Don’t forget that in React we use aclassName
prop instead ofclass
.Note that I added a
"layout"
class to the overall surrounding element of the entire element in order to set the overall page layout using a grid layout and assigned areas.Example CSS:
You will then adjust the routes to pass the sidebar and header components to the layout route each.