Router
This is the built-in router for Redwood apps. It takes inspiration from Ruby on Rails, React Router, and Reach Router, but is very opinionated in its own way.
The router is designed to list all routes in a single file, with limited nesting. We prefer this design, as it makes it very easy to track which routes map to which pages.
Router and Route
The first thing you need is a Router
. It will contain all of your routes. The router will attempt to match the current URL to each route in turn, and only render those with a matching path
. The only exception to this is the notfound
route, which can be placed anywhere in the list and only matches when no other routes do.
notfound
route can't be nested in a Set
If you want to wrap your custom notfound page in a Layout
, then you should add the Layout
to the page instead. See customizing the NotFoundPage.
Each route is specified with a Route
. Our first route will tell the router what to render when no other route matches:
import { Router, Route } from '@redwoodjs/router'
const Routes = () => (
<Router>
<Route notfound page={NotFoundPage} />
</Router>
)
export default Routes
The router expects a single Route
with a notfound
prop. When no other route is found to match, the component in the page
prop will be rendered.
To create a route to a normal Page, you'll pass three props: path
, page
, and name
:
<Route path="/" page={HomePage} name="home" />
The path
prop specifies the URL path to match, starting with the beginning slash. The page
prop specifies the Page component to render when the path is matched. The name
prop is used to specify the name of the named route function.
Private Routes
Some pages should only be visible to authenticated users.
We support this using private <Set>
s or the <Private>
component. Read more further down.
Sets of Routes
You can group Routes into sets using the Set
component. Set
allows you to wrap a set of Routes in another component or array of components—usually a Context, a Layout, or both:
import { Router, Route, Set } from '@redwoodjs/router'
import BlogContext from 'src/contexts/BlogContext'
import BlogLayout from 'src/layouts/BlogLayout'
const Routes = () => {
return (
<Router>
<Set wrap={[BlogContext, BlogLayout]}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
<Route path="/contact" page={ContactPage} name="contact" />
<Route path="/blog-post/{id:Int}" page={BlogPostPage} name="blogPost" />
</Set>
</Router>
)
}
export default Routes
The wrap
prop accepts a single component or an array of components. Components are rendered in the same order they're passed, so in the example above, Set expands to:
<BlogContext>
<BlogLayout>
<Route path="/" page={HomePage} name="home" />
// ...
</BlogLayout>
</BlogContext>
Conceptually, this fits with how we think about Context and Layouts as things that wrap Pages and contain content that’s outside the scope of the Pages themselves. Crucially, since they're higher in the tree, BlogContext
and BlogLayout
won't rerender across Pages in the same Set.
There's a lot of flexibility here. You can even nest Sets
to great effect:
import { Router, Route, Set, Private } from '@redwoodjs/router'
import BlogContext from 'src/contexts/BlogContext'
import BlogLayout from 'src/layouts/BlogLayout'
import BlogNavLayout from 'src/layouts/BlogNavLayout'
const Routes = () => {
return (
<Router>
<Set wrap={[BlogContext, BlogLayout]}>
<Route path="/" page={HomePage} name="home" />
<Route path="/about" page={AboutPage} name="about" />
<Route path="/contact" page={ContactPage} name="contact" />
<Set wrap={BlogNavLayout}>
<Route path="/blog-post/{id:Int}" page={BlogPostPage} name="blogPost" />
</Set>
</Set>
</Router>
)
}