GregH
GregH

Reputation: 5457

React: Using different layouts for different routes

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

Answers (2)

leosteffen
leosteffen

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

Mark
Mark

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

Related Questions