73

I am a beginner in React JS and would like to develop a react router based navigation for my Dashboard. The mockup is as follows:

Mockup

My app.js code which I created to try routing is as follows:

import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Link } from 'react-router'
import Login from './components/Login.js';

const App = React.createClass({
  render() {
    return (
      <div>
        <h1>App</h1>
        <ul>
          <li><Link to="/login">Login</Link></li>
          <li><Link to="/inbox">Inbox</Link></li>
        </ul>
        {this.props.children}
      </div>
    )
  }
})


render((
  <li>
  <Router>
    <Route path="/" component={App}>
      <Route path="login" component={Login} />
    </Route>
  </Router>
  </li>
), document.getElementById('placeholder'))

How do I create the navigation as shown in the mockup ?

cucucool
  • 3,777
  • 8
  • 48
  • 63
  • What is the question? Do you want to know how to create a component? What does routing have to do with that? – Daniel B Jan 05 '16 at 10:59
  • 3
    I would like to create the navigation using react router as mentioned in the mockup. – cucucool Jan 05 '16 at 17:06
  • 1
    Have you tried Google? Your question doesn't have a specific problem that can be solved but instead a very general problem. Just look up how to create a component and you're good to go! – Daniel B Jan 05 '16 at 18:11
  • take a look at https://www.npmjs.com/package/react-nav-bar it might make your life a little easier – Neta Meta Jun 30 '16 at 20:42

4 Answers4

75

Note The accepted is perfectly fine - but wanted to add a version4 example because they are different enough.

Nav.js

  import React from 'react';
  import { Link } from 'react-router';

  export default class Nav extends React.Component {
    render() {    
      return (
        <nav className="Nav">
          <div className="Nav__container">
            <Link to="/" className="Nav__brand">
              <img src="logo.svg" className="Nav__logo" />
            </Link>

            <div className="Nav__right">
              <ul className="Nav__item-wrapper">
                <li className="Nav__item">
                  <Link className="Nav__link" to="/path1">Link 1</Link>
                </li>
                <li className="Nav__item">
                  <Link className="Nav__link" to="/path2">Link 2</Link>
                </li>
                <li className="Nav__item">
                  <Link className="Nav__link" to="/path3">Link 3</Link>
                </li>
              </ul>
            </div>
          </div>
        </nav>
      );
    }
  }

App.js

  import React from 'react';
  import { Link, Switch, Route } from 'react-router';
  import Nav from './nav';
  import Page1 from './page1';
  import Page2 from './page2';
  import Page3 from './page3';

  export default class App extends React.Component {
    render() {    
      return (
        <div className="App">
          <Router>
            <div>
              <Nav />
              <Switch>
                <Route exactly component={Landing} pattern="/" />
                <Route exactly component={Page1} pattern="/path1" />
                <Route exactly component={Page2} pattern="/path2" />
                <Route exactly component={Page3} pattern="/path3" />
                <Route component={Page404} />
              </Switch>
            </div>
          </Router>
        </div>
      );
    }
  }

Alternatively, if you want a more dynamic nav, you can look at the excellent v4 docs: https://reacttraining.com/react-router/web/example/sidebar

Edit

A few people have asked about a page without the Nav, such as a login page. I typically approach it with a wrapper Route component

  import React from 'react';
  import { Link, Switch, Route } from 'react-router';
  import Nav from './nav';
  import Page1 from './page1';
  import Page2 from './page2';
  import Page3 from './page3';

  const NavRoute = ({exact, path, component: Component}) => (
    <Route exact={exact} path={path} render={(props) => (
      <div>
        <Header/>
        <Component {...props}/>
      </div>
    )}/>
  )

  export default class App extends React.Component {
    render() {    
      return (
        <div className="App">
          <Router>
              <Switch>
                <NavRoute exactly component={Landing} pattern="/" />
                <Route exactly component={Login} pattern="/login" />
                <NavRoute exactly component={Page1} pattern="/path1" />
                <NavRoute exactly component={Page2} pattern="/path2" />
                <NavRoute component={Page404} />
              </Switch>
          </Router>
        </div>
      );
    }
  }
Chris
  • 54,599
  • 30
  • 149
  • 186
  • 3
    The current v4 router only allows a single child. I fixed this in my app by wrapping the Router Nav/Switch children with a single
    . I then had to put Nav into a before Switch so it would receive route props history,match, and location. Please update your answer.
    – Glenn Aug 12 '17 at 17:13
  • 6
    How does this work if you have a login page? Probably don't want a navbar showing up on the login page. is there a way around this? – Chad Greenburg Jan 09 '18 at 03:28
  • @ChadGreenburg Could you ask a seperate question and link it here - it would be too difficult to answer in comments – Chris Jan 25 '18 at 06:49
  • how do i set conditional 'active' class in nav bar? – Shekhar Joshi Apr 15 '18 at 20:09
  • What if I want the navbar on every page, but not at the top of the page on page 1? For example, I want my navbar below the jumbotron on the home page/page 1. – cDub Oct 29 '18 at 23:35
  • Raise a new question please, too difficult to answer in the comments – Chris Oct 29 '18 at 23:45
  • Thanks for posting the answer. What if in the landing page I want to have some default content as well? – Si8 Jul 08 '19 at 02:25
  • 1
    @Si8 I think I would make a landing route. For example: `` – Chris Jul 08 '19 at 05:19
  • My Url is changing but the component isn't changing. Would you like me to post my code in a question? Thanks – Si8 Jul 08 '19 at 16:25
  • @Si8 I would say maybe a new question for something like that – Chris Jul 08 '19 at 23:05
  • @Chris Thanks for your answer - What if I want to render a component with props, how do I edit NavRoute wrapper to accept that? – hoohoo-b Jul 31 '19 at 05:48
  • Should Link be imported from 'react-router-dom' instead? This may have changed since you gave your answer. – Alex Aug 27 '20 at 19:52
  • @Alex I don't have the docs handy (ie. I'm too lazy to look). Are you you referring to RRv4 or RRv5? – Chris Aug 28 '20 at 03:44
  • Good point, I was referring to RRv5, so I guess it's not really pertinent to your answer which is for v. 4. – Alex Aug 29 '20 at 16:53
  • Thanks @Alex . If I get time I will checkout RRv5 and update the answer. Cheers – Chris Aug 30 '20 at 03:04
57

Yes, Daniel is correct, but to expand upon his answer, your primary app component would need to have a navbar component within it. That way, when you render the primary app (any page under the '/' path), it would also display the navbar. I am guessing that you wouldn't want your login page to display the navbar, so that shouldn't be a nested component, and should instead be by itself. So your routes would end up looking something like this:

<Router>
  <Route path="/" component={App}>
    <Route path="page1" component={Page1} />
    <Route path="page2" component={Page2} />
  </Route>
  <Route path="/login" component={Login} />
</Router>

And the other components would look something like this:

var NavBar = React.createClass({
  render() {
    return (
      <div>
        <ul>
          <a onClick={() => history.push('page1') }>Page 1</a>
          <a onClick={() => history.push('page2') }>Page 2</a>
        </ul>
      </div>
    )
  }
});

var App = React.createClass({
  render() {
    return (
      <div>
        <NavBar />
        <div>Other Content</div>
        {this.props.children}
      </div>
    )
  }
});
JTaub
  • 1,273
  • 11
  • 16
  • 31
    Why use history.push instead of ? – Erwin Mayer Oct 26 '16 at 07:38
  • 1
    where does history get loaded in? – Matt Catellier Dec 06 '16 at 16:23
  • 1
    `react-router` builds on `history`, so it enters the scene with this line `import { Router, Route, Link } from 'react-router'`. Instead of using `history.push` for the links explicitly, you could also use [react-router's ``](https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/Link.md) element. – martin-martin Sep 16 '17 at 19:40
21

React router version 6+ 2021 Routes With/Without Navbars

import { Outlet, Route, Routes } from "react-router-dom";
// your components here 

const App = () => {
  
  return (
    <>
      <Routes>
        {/* Routes that needs a navbar will need to go as children of this Route component */}
        <Route path="/" element={<LayoutsWithNavbar />}>
          <Route path="/" element={<div>Home screen</div>} />
          <Route path="/welcome" element={<Welcome />} />
          <Route path="/something" element={<Somethinggg />} />
          <Route path="/somethingProtected" element={<YourCustomProtectedRoute component={Someone}/>} />
          <Route path="/something/:id" element={<ProtectedRoute id component={SomethingById}/>} />
        </Route>

        {/* Routes without a navbar you can add them here as normal routes */}
        <Route
          path="/idontneednavbar"
          element={<ProtectedRoute component={ProviderRegistrationInfo} />}
        />
      </Routes>
    </>
  );

  function LayoutsWithNavbar() {
    return (
      <>
        {/* Your navbar component */}
        <Navbar />
  
        {/* This Outlet is the place in which react-router will render your components that you need with the navbar */}
        <Outlet /> 
        
        {/* You can add a footer to get fancy in here :) */}
      </>
    );
  }
  

How it works

The LayoutsWithNavbar component will render the navbar with any component you need with a navbar. You can find an example in the official react-router v6 docs here: https://reactrouter.com/docs/en/v6/getting-started/overview#nested-routes

Learn more about the Outlet component: https://reactrouter.com/docs/en/v6/getting-started/concepts#outlets

LuisDev99
  • 1,697
  • 17
  • 13
2

For @Chris 's answer to work in a functional component. Here is the answer React-router, router-dom versions v5.2.0

  import React from 'react';
  import { Link, Switch, Route } from 'react-router-dom';
  import Header from './header';
  import Footer from '.footer';
  import Page1 from './page1';
  import Page2 from './page2';
  import Page3 from './page3';
  import Loading from './Loading'; // a page to show spinner 

const Dashboard = React.lazy(() => import('../pages/Dashboard'));
// if you have an admin dashboard to load lazily

  const NavRoute = ({exact, path, component: Component}) => (
    <Route exact={exact} path={path} render={(props) => (
      <div>
        <Header/>
        <Component {...props}/>
        <Footer/>
      </div>
    )}/>
  )

  function App() {   
      return (
        <div>
          <Suspense fallback={<Loading />}>
              <Switch>
                <NavRoute exact path="/" component={Landing}  />
                <Route exact path="/admin/dashboard" component={Dashboard}/>
                <Route exact path="/" component={Login} />
                <NavRoute exact path="/path1" component={Page1} />
                <NavRoute exact path="/path2" component={Page2} />
                <NavRoute component={Page404} />
              </Switch>
          </Suspense>
        </div>
      );
  }

export default App;
binrebin
  • 357
  • 4
  • 16