Reputation: 5457
I am encountering a somewhat odd issue try to split my components into using two different layouts. I have 2 layouts: PublicLayout
and Layout
where my App.js
has my routes defined as such:
render() {
return (
<ApolloProvider client={client}>
<Layout>
<Route path="/articles" component={ArticlesIndex} exact={true} />
<Route
path="/articles/create"
component={ArticlesCreate}
exact={true}
/>
<Route
path="/articles/edit/:id"
component={ArticlesEdit}
exact={true}
/>
</Layout>
<PublicLayout>
<Route exact path="/" component={Home} exact={true} />
<Route
path="/articles/view/:id"
component={ArticlesView}
exact={true}
/>
</PublicLayout>
</ApolloProvider>
);
}
Here is what Layout
looks like:
<div className="container">
<Grid fluid>
<Row>
<Col sm={12}>
{this.props.children}
</Col>
</Row>
</Grid>
</div>
All of my routes/components that are inside the PublicLayout
tag render and operate as expected. However, all of my routes/components which use my Layout
component are rendered as expected but then have the PublicLayout
rendered below them. I'm guessing PublicLayout
is being included on these pages since it appears with no qualifying conditions after the Layout
section. How can I overcome this and only render the PublicLayout
on the routes which it includes?
All help is appreciated.
UPDATE: I've solved my issue by using the following which allowed me to define arbitrarily, on a per-route basis which layout each route gets:
function renderWithLayout(Component, Layout, props) {
return <Layout><Component {...props}/></Layout>
}
export default class App extends Component {
displayName = App.name;
render() {
return (
<ApolloProvider client={client}>
<Route
path="/articles"
render={(props) => renderWithLayout(ArticlesIndex, Layout, props)}
exact={true}
/>
<Route
path="/articles/create"
render={(props) => renderWithLayout(ArticlesCreate, Layout, props)}
exact={true}
/>
<Route
path="/articles/edit/:id"
render={(props) => renderWithLayout(ArticlesEdit, Layout, props)}
exact={true}
/>
<Route
path="/"
render={(props) => renderWithLayout(Home, PublicLayout, props)}
exact={true}
/>
<Route
path="/articles/view/:id"
render={(props) => renderWithLayout(ArticlesView, PublicLayout, props)}
exact={true}
/>
</ApolloProvider>
);
}
}
Upvotes: 0
Views: 324
Reputation: 362
Unless I am missing any important detail here, it looks like react is doing exactly what your render function is telling it to do. There is no conditional rendering there, so you're always going to have Layout and PublicLayout.
Solve it by adding a conditional around them. You could simply extract into two different functions and render one or the other based on whatever condition you'd like to drive that output.
Upvotes: 0
Reputation: 1679
Use conditional rendering. Let's pretend loggedIn
is what you use to keep track of if a user has been authenticated or not.
render() {
return {
<ApolloProvider client={client}>
{ loggedIn ? (
<Layout>
<Route path="/articles" component={ArticlesIndex} exact={true} />
<Route
path="/articles/create"
component={ArticlesCreate}
exact={true}
/>
<Route
path="/articles/edit/:id"
component={ArticlesEdit}
exact={true}
/>
</Layout>
) : (
<PublicLayout>
<Route exact path="/" component={Home} exact={true} />
<Route
path="/articles/view/:id"
component={ArticlesView}
exact={true}
/>
</PublicLayout>
)}
</ApolloProvider>
);
}
For other examples and solutions https://reactjs.org/docs/conditional-rendering.html
Upvotes: 1