Reputation: 1765
I would like to have a global No Match route to handle all 404s. Once signed in, all primary views fall inside a layout wrapped with a header and footer. Though the NotFound component should render outside this layout.
Here is a link to a "working" code sample
Here is a simplified example of the code:
const App = () => (
<Switch>
<Route path="/register" component={Register} />
<Route path="/signin" component={SignIn} />
<Route path="/" component={Home} />
<Route component={NotFound} />
</Switch>
);
const Home = () => (
<div>
<Header />
<main>
<Switch>
<Route exact path="/" component={Main} />
<Route path="/list" component={List} />
<Route path="/tasks" component={Tasks} />
</Switch>
</main>
<Footer />
</div>
);
The above code sample works in rendering the layout as I wish, but renders an empty layout on non matching urls. If I set the App root path to exact
than I can get the NotFound but lose the Home routes
Though variations of using/not-using exact
on the roots, moving the roots to the bottom of the list of Route
s I can get portions of the expected behavior to work, but not all of it working in concert.
If I visit "/" I expect to see:
Some Header Thing
Home
Some Footer Thing
If I visit "/list" I expect to see:
Some Header Thing
List
Some Footer Thing
If I visit "/register" I expect to see:
Register
If I visit "/foobar" I expect to see:
Not Found
Upvotes: 0
Views: 1379
Reputation: 71
This below will get the routes working, with relatively minor tweaks to your code, and as I don't want to assume too much I'm hesitant to restructure things a lot. But as you can see, this results in using the 'Home' component to lead into all the sections with headers and footers, with 'Not Found' catching the rest. However, it does flatten things a lot which could get unwieldy with a lot of routes.
const App = () => (
<BrowserRouter>
<Switch>
<Route path="/register" render={() => <div>Register</div>} />
<Route path="/signin" render={() => <div>Sign in</div>} />
<Route path="/list" component={Home} />
<Route path="/tasks" component={Home} />
<Route exact path="/" component={Home} />
<Route render={() => <div>Not Found</div>} />
</Switch>
</BrowserRouter>
);
const Home = () => (
<div>
<header>Some Header Thing</header>
<main>
<Switch>
<Route path="/list" render={() => <div>List</div>} />
<Route path="/tasks" render={() => <div>Tasks</div>} />
<Route path="/" render={() => <div>Home</div>} />
</Switch>
</main>
<footer>Some Footer Thing</footer>
</div>
);
(Also, just realised I used the sample codeSandbox you gave as a model - not your Qs – sorry about that.)
Another way of thinking about the structure would be to follow your very direct and good description a little more literally. You write that there should be first a registered-and-signed-in user, then the various routes of the site should appear after that is true. Rather than thinking of this as a routing question, think of it as a props
question – is there a defined user
props?, if so render the route's components, if not render the register/sign components. You could use a ternary to check for the existence of a user in the App
, something like:
const App = ({user}) => (
<div>
{ user ? Home : Signin }
</div>
)
where Home
would render your a version of your existing component and Signin
would take you into a component similar to the App
component. You could also leave the 'Not Found' route in App
.
Upvotes: 1