2

I have a situation where I have two main 'shells' for pages in my app. The first shell is for the 'unauth' pages login flow (background image, material-ui paper), and the second shell is the main dashboard (navbar, sidebar etc).

The following code is my attempt at simplifying the issue I am running into. Could someone please show me how to properly achieve this with react-router-dom?

  <BrowserRouter>
    <Switch>
      <Route component={Shell1}>
        <Route path="/test1" exact component={() => <div>Test 1</div>} />
        <Route path="/test2" exact component={() => <div>Test 2</div>} />
      </Route>
      <Route component={Shell2}>
        <Route path="/test3" exact component={() => <div>Test 3</div>} />
        <Route path="/test4" exact component={() => <div>Test 4</div>} />
      </Route>
    </Switch>
  </BrowserRouter>

I got this attempt from another StackOverflow post here, but this code above does NOT work. When navigating to /test1, Shell1 (just a div that says Shell1) does NOT display, and /test3 + /test4 do not work at all.

Here's a codeSandbox demonstrating: https://codesandbox.io/s/react-example-362ow

Thanks in advance.

JakeD
  • 407
  • 2
  • 7
  • 19
  • Do you really need the switch? `A looks through its children s and renders the first one that matches the current URL.` – artm Nov 04 '19 at 01:48
  • @artm Tested without the switch and still not seeing the Shells rendered. I actually thought that without the switch, both shells might be rendered, but that wasn't the case. – JakeD Nov 05 '19 at 03:50

1 Answers1

1

Basically you'll want to nest routes like so, where a parent component Route wraps children Routes.

Here's are some examples where authentication is required: https://codesandbox.io/s/yqo75n896x (using Redux state) or https://codesandbox.io/s/5m2690nn6n (using React state)

Working example:

Edit Nested Routes Example


index.js

import ReactDOM from "react-dom";
import React, { Fragment } from "react";
import { BrowserRouter, Route, Switch, Link } from "react-router-dom";
import Shell1 from "./shell1";
import Shell2 from "./shell2";

function NavBar() {
  return (
    <Fragment>
      <Link to="/shell1/test1">Test1</Link>
      <br />
      <Link to="/shell1/test2">Test2</Link>
      <br />
      <Link to="/shell2/test3">Test3</Link>
      <br />
      <Link to="/shell2/test4">Test4</Link>
    </Fragment>
  );
}

function App() {
  return (
    <BrowserRouter>
      <div>
        <NavBar />
        <Route path="/shell1" component={Shell1} />
        <Route path="/shell2" component={Shell2} />
      </div>
    </BrowserRouter>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

shell1.js

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

export default function Shell1({ match }) {
  return (
    <div>
      <div>Shell 1</div>
      <Switch>
        <Route
          exact
          path={`${match.url}/test1`}
          component={() => <div>Test 1</div>}
        />
        <Route
          exact
          path={`${match.url}/test2`}
          component={() => <div>Test 2</div>}
        />
      </Switch>
    </div>
  );
}

shell2.js

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

export default function Shell2({ match }) {
  return (
    <div>
      <div>Shell 2</div>
      <Switch>
        <Route
          exact
          path={`${match.url}/test3`}
          component={() => <div>Test 3</div>}
        />
        <Route
          exact
          path={`${match.url}/test4`}
          component={() => <div>Test 4</div>}
        />
      </Switch>
    </div>
  );
}
Matt Carlotta
  • 18,972
  • 4
  • 39
  • 51
  • Thanks for your response. Might there be a way to do this without requiring the URL string to include /shell1 and /shell2? I considered the idea of having all my authenticated routes (the first shell) starting with /auth and the others with /unauth, but I don't think this is ideal. – JakeD Nov 05 '19 at 03:48
  • @Jaked222 Will this do? Just a fork of Matt's code https://codesandbox.io/s/nested-routes-example-ghxsv – artm Nov 05 '19 at 05:11
  • @Jaked222 - I'll have to think about it. I know you can create a HOC wrapper with context or redux state and conditionally render a route based upon some sort of variable. However, I tend avoid HOC wrappers. Regardless, you can find a similar example here: https://stackoverflow.com/a/44854959/7376526 (1st example -- where a HOC wraps the component route component). – Matt Carlotta Nov 05 '19 at 05:52