12

I want to show Navbar only for this url: /contact, /services. And I don't want to show Navbar for /signin. For this moment this is what I have:

import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';

import PublicLayout from './components/layouts/PublicLayout';
import SigninLayout from './components/layouts/SigninLayout';

import Main from './components/pages/Main';
import Services from './components/pages/Services';
import Contact from './components/pages/Contact';

class App extends Component {
    render() {
        return (
            <BrowserRouter>
                <div className="App">
                  <Switch>                    
                    <PublicLayout>
                            <Route exact path='/' component={Main} />
                            <Route exact path='/services' component={Services} />
                            <Route exact path='/contact' component={Contact} />
                    </PublicLayout>
                    <SigninLayout>
                            <Route exact path='/signin' component={Signin} />
                    </SigninLayout>
                  </Switch>
                </div>
            </BrowserRouter>
        );
    }
}

export default App;

When I go to /signin url it still gives me Navbar. So guys - how do you render different layouts for different pages in React? Please help!

UPD: My PublicLayout Code:

import React, { Component } from 'react';
import Navbar from '../nav/Navbar';

class PublicLayout extends Component {
    state = {
        items: [
            { id: 1, name: 'Услуги', link: '/services' },
            { id: 2, name: 'Как это работает?', link: '/contacts' },
            { id: 3, name: 'Войти', link: '/signin' },
        ]
    }

    render() {
        return (
            <div>
                <Navbar items={ this.state.items } />
                { this.props.children }
            </div>
        );
    }
}

export default PublicLayout;

My SignInLayout code:

import React, { Component } from 'react';

class SigninLayout extends Component {
    state = {

    }

    render() {
        return (
            <div>
                { this.props.children }
            </div>
        );
    }
}

export default SigninLayout;

My SignIn component:

import React, { Component } from 'react';

class Signin extends Component {
    state = {

    }

    render() {
        return (
            <div>
                <h1>Войти</h1>
                <form>
                    <input type="text" placeholder="укажите e-mail" />
                    <input type="text" placeholder="укажите пароль" />
                    <button>Войти</button>
                </form>
            </div>
        );
    }
}

export default Signin;
Nastro
  • 1,719
  • 7
  • 21
  • 40
  • I've only ever done this rather badly; I rendered a component at the top level, and then changed it's rendering conditionally based on the route. I'll be interested to see some better solutions – OliverRadini Sep 24 '18 at 13:41
  • Can you show us the SigninLayout, PublicLayout and Signin component code? – c-chavez Sep 24 '18 at 13:43
  • @c-chavez updated my question with code samples. Thanks for helping me. – Nastro Sep 24 '18 at 13:51
  • For latter users, pls check this code example https://codesandbox.io/s/react-router-v5-multiple-layout-forked-y5i1e – unicorn Nov 13 '21 at 14:40

1 Answers1

13

You can achieve this by first choosing which layout to render using your switch statement, and then moving the routing for components that should be rendered inside that layout to inside the layout component.

As a very basic example, your App component could have:

<BrowserRouter>
  <div className="App">
    <Switch>
      <Route path="/signin" component={PrivateLayout} />
      <Route path="/" component={PublicLayout} />
    </Switch>
  </div>
</BrowserRouter>

Now inside PublicLayout, you can render the Nav and also create some new routes e.g.

class PublicLayout extends Component {
  render() {
    return (
      <div>
        <h1>Public Place</h1>
        <Navbar items={[]} />
        <Switch>
          <Route exact path='/' component={Main} />
          <Route exact path='/services' component={Services} />
          <Route exact path='/contact' component={Contact} />
        </Switch>
      </div>
    );
  }
}

export default PublicLayout;

...and in PrivateLayout you can render a set of routes without the NavBar e.g.

class PrivateLayout extends Component {
  render() {
    return (
      <div>
        <h1>Private Place</h1>
        <Switch>
          <Route exact path="/signin" component={Signin} />
          <Route exact path="/signin/otherpath" component={OtherPrivateComponent} />
        </Switch>
      </div>
    );
  }
}

export default PrivateLayout;

Here it is all in one file, which you can also see on this codesandbox:

import React, { Component } from "react";
import ReactDOM from "react-dom";

import { BrowserRouter, Route, Switch } from "react-router-dom";

const NavBar = props => <div>Nav Bar</div>;

class PrivateLayout extends Component {
  render() {
    return (
      <div>
        <h1>Private</h1>
        <Switch>
          <Route exact path="/signin" render={() => <h2>Signin</h2>} />
          <Route
            exact
            path="/signin/otherpath"
            render={() => <h2>Signin Other</h2>}
          />
        </Switch>
      </div>
    );
  }
}

class PublicLayout extends Component {
  render() {
    return (
      <div>
        <h1>Public Place</h1>
        <NavBar />
        <Switch>
          <Route exact path="/" render={() => <h2>Main Page</h2>} />
        </Switch>
      </div>
    );
  }
}

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Switch>
          <Route path="/signin" component={PrivateLayout} />
          <Route path="/" component={PublicLayout} />
        </Switch>
      </BrowserRouter>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Tom
  • 2,734
  • 2
  • 22
  • 39
  • Yep, I tested it locally. What do you see when you try that means it isn't working? – Tom Sep 24 '18 at 14:56
  • 1
    It doesn't render anything except main page with navbar and main page content. – Nastro Sep 24 '18 at 14:57
  • This is how my App look like: http://prntscr.com/ky4r4w This is PublicLayout http://prntscr.com/ky4rcd – Nastro Sep 24 '18 at 15:00
  • I've updated my answer with both a link to a working example, and a code example of this working with several components inside a single file. – Tom Sep 24 '18 at 15:03
  • I found an error! in App class. So if it won't work. But IF without it will. Can you explain why? – Nastro Sep 24 '18 at 15:29
  • 1
    For all those that will use this article, please make sure that you define the "/signin" route before the "/" route. The "/" route should always be the last route defined. – Ionut Flavius Pogacian Aug 28 '19 at 08:12