Search code examples
javascriptreactjsreact-routerreact-router-dom

How to route pages with common component and a separate page without this common component using react router


I have multiple pages that have the navbar and the sidebar as component in my app.js and I have another page such as my login page that does not have this navbar and sidebar. How do I make the routing using react-router so that the login page will be entirely a different route page without the sidebar and navbar, while the other multiple pages will have the sidebar and navbar on the app.js?

Below is what I have done so far but the dashboard page inside the route is not displaying.

app.js

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route path='/' element={(
          <>
            <Container>
              <SideBar />
              <Main>
                <Navbar />
                <Wrapper>
                  <Route path='landing' element={<Dashboard/>} />
                  <Route path='pricing' element={<Price/>} />
                </Wrapper>
              </Main>
            </Container>
          </>
        )}/>  
      </Routes>
    </Router>
  );
}

export default App;

Right now the whole page is not working again. I am currently getting the is error message:

Uncaught runtime errors:
×
ERROR
A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
    at invariant (http://localhost:3000/static/js/bundle.js:17236:11)
    at Route (http://localhost:3000/static/js/bundle.js:66637:78)
    at renderWithHooks (http://localhost:3000/static/js/bundle.js:51633:22)
    at mountIndeterminateComponent (http://localhost:3000/static/js/bundle.js:54919:17)
    at beginWork (http://localhost:3000/static/js/bundle.js:56215:20)
    at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:41225:18)
    at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:41269:20)
    at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:41326:35)
    at beginWork$1 (http://localhost:3000/static/js/bundle.js:61200:11)
    at performUnitOfWork (http://localhost:3000/static/js/bundle.js:60447:16)

Is there a better approach to this?


Solution

  • Issue

    The issue is that you are trying to render descendent routes that are not wrapped in a Routes component.

    Solution w/ Descendent Routes

    Wrap the descendent routes in the Routes component and ensure the parent route appends the "*" wildcard matcher to the end of its path so all descendent routes can also be matched and rendered.

    import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
    
    function App() {
      return (
        <Router>
          <Routes>
            <Route path="/login" element={<Login />} />
            <Route
              path="/*"
              element={(
                <Container>
                  <SideBar />
                  <Main>
                    <Navbar />
                    <Wrapper>
                      <Routes>
                        <Route path='landing' element={<Dashboard />} />
                        <Route path='pricing' element={<Price/>} />
                      </Routes>
                    </Wrapper>
                  </Main>
                </Container>
              )} 
            />  
          </Routes>
        </Router>
      );
    }
    
    export default App;
    

    Solution w/ Nested Routes

    You could alternatively create a layout route component that renders an Outlet for nested routes to render their content into.

    Example:

    import {
      BrowserRouter as Router,
      Routes,
      Route,
      Outlet
    } from 'react-router-dom';
    
    const Layout = () => (
      <Container>
        <SideBar />
        <Main>
          <Navbar />
          <Wrapper>
            <Outlet />
          </Wrapper>
        </Main>
      </Container>
    );
    
    function App() {
      return (
        <Router>
          <Routes>
            <Route path="/login" element={<Login />} />
            <Route path="/" element={<Layout />}>
              <Route path='landing' element={<Dashboard />} />
              <Route path='pricing' element={<Price/>} />
            </Route>
          </Routes>
        </Router>
      );
    }
    
    export default App;