I'm trying to render most of my routes as children of an AppShell
component, which contains a navbar. But I want to render my 404 route as a standalone component not wrapped in AppShell
.
It was easy with v2:
<Router>
<Route component={AppShell}>
<Route path="/about" component={About} />
<Route path="/" component={Home} />
</Route>
<Route path="*" component={NotFound} />
</Router>
Everything works as desired:
/
renders<AppShell><Home /></AppShell>
/about
renders<AppShell><About /></AppShell>
/blah
renders<NotFound />
But I can't figure out how to do it with v4:
Right now I'm doing this, but the problem is it renders AppShell
(with no children, but still a navbar):
const Routes = () => (
<div>
<AppShell>
<Match exactly pattern="/" component={Home} />
<Match pattern="/about" component={About} />
</AppShell>
<Miss component={NotFound} />
</div>
)
With this:
/
renders<div><AppShell><Home /></AppShell></div>
(good)/about
renders<div><AppShell><About /></AppShell></div>
(good)/blah
renders<div><AppShell /><NotFound /></div>
(problem -- I want to get rid of the<AppShell />
)
Using an array pattern
works if there's no root route:
const InAppShell = (): React.Element<any> => (
<AppShell>
<Match pattern="/about" component={About} />
<Match pattern="/contact" component={Contact} />
</AppShell>
)
const App = (): React.Element<any> => (
<div>
<Match pattern={['/contact', '/about']} component={InAppShell} />
<Miss component={NotFound} />
</div>
)
And using an array pattern
with exactly
works with the root route:
But then I have to put all possible child routes in the pattern
array...
const InAppShell = (): React.Element<any> => (
<AppShell>
<Match exactly pattern="/" component={Home} />
<Match pattern="/about" component={About} />
</AppShell>
)
const App = (): React.Element<any> => (
<div>
<Match exactly pattern={["/", "/about"]} component={InAppShell} />
<Miss component={NotFound} />
</div>
)
But that would be pretty unwieldly in a large app with a bunch of routes.
I could make a separate Match
for /
:
const InAppShell = (): React.Element<any> => (
<AppShell>
<Match exactly pattern="/" component={Home} />
<Match pattern="/about" component={About} />
<Match pattern="/contact" component={Contact} />
</AppShell>
)
const App = (): React.Element<any> => (
<div>
<Match exactly pattern="/" component={InAppShell} />
<Match pattern={["/about", "/contact"]} component={InAppShell} />
<Miss component={NotFound} />
</div>
)
But this would remount <AppShell>
every time I transition to and from the home route.
There doesn't seem to be an ideal solution here; I think this is a fundamental API design challenge v4 will need to solve.
If only I could do something like <Match exactlyPattern="/" pattern={["/about", "/contact"]} component={InAppShell} />
...