-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
How do you create a Master Detail page? (v4) #3928
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
the basic example does this, doesn't it? |
Not exactly. I want to do something like: <Router>
<div className={'app-container'}>
<Switch>
<DefaultLayout>
<Route exact path={'/'} component={Dashboard} />
</DefaultLayout>
<EmptyLayout>
<Route component={NotFound} />
</EmptyLayout>
</Switch>
</div>
</Router> Where the app uses a different container component based on which route matches. EDIT: This works, but I'm not sure it's the best solution: const routes = [
{
exact: true,
path: '/',
component: Dashboard,
layout: DefaultLayout,
}, {
path: '/advertisers',
component: Advertisers,
layout: DefaultLayout,
},
];
const App = props => (
<Router history={history}>
<div className={'app-container'}>
<Switch>
{routes.map(route => (
<Route path={route.path} key={route.path} exact={route.exact}>
<route.layout>
<route.component />
</route.layout>
</Route>
))}
<Route>
<EmptyLayout>
<Route component={NotFound} />
</EmptyLayout>
</Route>
</Switch>
</div>
</Router>
); |
@LukeAskew Have you found a better solution so far? I've got the same issue here. The page layout is expected to contain a header and a sidebar in all cases except when it's 404. The trick with routes.map would work, but it would also generate multiple instances of the header and the sidebar, so when a user is switching between routes, the layout DOM goes through a deep refresh :–( |
@ryanflorence how would you solve this? It'd be great to have this case covered in the docs. |
const routes = [
{ path: '/one',
component: One
},
{ path: '/two',
component: Two
},
{ path: '/three',
component: Three
}
]
<Router>
<div>
<Switch>
{routes.map(route => (
<Route path={route.path} component={Header}/>
))}
</Switch>
<Switch>
{routes.map(route => (
<Route path={route.path} component={Sidebar}/>
))}
</Switch>
<Switch>
{routes.map(route => (
<Route path={route.path} component={route.component}/>
))}
<Route component={NoMatch}/>
</Switch>
</div>
</Router> There's a bug right now #4578 that will avoid the remounting of |
const routes = [
{ path: '/one',
Component: One,
Layout: Layout1
},
{ path: '/two',
Component: Two,
Layout: Layout2
},
{ path: '/three',
Component: Three,
Layout: Layout2
}
]
<Router>
<div>
<Switch>
{routes.map({ path, Layout, Component } => (
<Route path={route.path} render={(props) => (
<Layout {...props}>
<Component {...props}/>
</Layout>
)}/>
))}
</Switch>
</div>
</Router> |
Thanks for your reply @ryanflorence – this is close to what I was looking for, assuming that the componets are reused. What would be good as well is to be able to control that top-level // /
<LayoutForPageWithContent>
<Header />
<Sidebar />
<Home />
</LayoutForPageWithContent>
// /about
<LayoutForPageWithContent>
<Header />
<Sidebar />
<About />
</LayoutForPageWithContent>
// /cart
<LayoutForPageWithContent>
<Header />
<Sidebar />
<Cart />
</LayoutForPageWithContent>
// ...
// /404
<LayoutForPageWithError>
<Error404 />
</LayoutForPageWithError> UPD: Header and Sidebar can be omitted, because they can be a part of |
const routes = [
{ path: '/',
exact: true,
component: Home
},
{ path: '/about',
component: About,
},
{ path: '/cart',
component: Three,
}
]
<Router>
<Switch>
{routes.map({ path, exact, component: Comp } => (
<Route path={path} exact={exact} render={(props) => (
<LayoutWithSidebarAndHeader {...props}>
<Comp {...props}/>
</LayoutWithSidebarAndHeader>
)}/>
))}
<Route component={Error404}/>
</Switch>
</Router> |
@ryanflorence this solution wont reuse |
there's a bug in switch #4578 |
I'm not sure if that bug is related. Reusing I don't see any solution in the current API, but I may be wrong. Looks like the only place the wrapper can be toggled is in <Switch wrapperComponent={({whatever}) => (whatever ? LayoutWithSidebarAndHeader : LayoutForPageWithError)}>
<Route exactly path="/" component={Home} />
<Route exactly path="/about" component={About} />
<Route exactly path="/cart" component={Cart} />
<Route component={Error404} />
</Switch> It's ugly, but at least it gives a chance to really reuse the layout in the situation above, which is not the same as reusing peer neighbours like |
It's not a different story. It's fixed on the v4 branch. |
Just updated to v4.0.0-beta.7 and can confirm that shared layout wrappers are reused perfectly now! Checked this by rendering a random Two caveats to share:
{routes.map(({ path, exact, content: ContentComponent }) => (
<Route
// NO key={path} etc. here!
path={path}
exact={exact}
render={(props) => (
<Layout {...props}>
<ContentComponent {...props} />
</Layout>
)}
/>
))} Thanks for your previous responses @ryanflorence! I enjoy V4 API more and more! UPD: Absence of |
@kachkaev you shouldn't be installing |
How the approach, is their any backlog issue if I'll try like this.
or how can I achieve this in a better way. |
while this was pretty easy in previous versions
|
@ankibalyan Have you tried this:
@timdorr it does not seem that this issue should be closed. Based on the basic example one would need to create |
I tried with this approach: const DefaultLayout = ({children}) => (
<div>
<Header/>
{children}
</div>
);
<Router>
<Switch>
<Route path="/checkout" exact component={Checkout}/>
<DefaultLayout>
<Switch>
<Route path="/" exact component={Home}/>
<Route path="/products" component={Products}/>
<Route path="/product/:item" component={ProductSingle}/>
<Route path="/cart" component={Cart}/>
<Route path="/login" component={Login}/>
<Route path="/register" component={Register}/>
<Route path="/forgetpass" component={ForgetPass}/>
</Switch>
</DefaultLayout>
</Switch>
</Router> |
I used this approach <Provider store={store}>
<ConnectedRouter history={history}> // this is from connected-react-router for my sagas
<Switch>
{routes.map(({ path, exact, component: Component }) => (
<Route
key={path}
path={path}
exact={exact}
render={props => (
<App {...props}>
<Component {...props} />
</App>
)}
/>
))}
</Switch>
</ConnectedRouter>
</Provider> And add side bar in App component with sidebars in routes.js Excellent !!! |
@eashish93 Unfortunately there doesn't seem to be a way to make that approach work with a layoutless fallthrough (e.g. 404), or with 2 or more different layouts. It works nicely for some use cases though. |
@kachkaev Thanks for the tip about not using keys. I was using keys and components were getting remounted on every route change. What's the best practice for |
I went through the docs multiple times but I'm still not sure how to create a layout that can share some common components.
How do you create a layout that always has a header and footer, and only body changes? And how do you create more routes within that body? (bonus)
thanks
The text was updated successfully, but these errors were encountered: