Server rendering is a bit different than in a client because you'll want to:
- Send
500
responses for errors - Send
30x
responses for redirects - Fetch data before rendering (and use the router to help you do it)
To facilitate these needs, you drop one level lower than the <Router>
API with:
match
to match the routes to a location without renderingRouterContext
for synchronous rendering of route components
It looks something like this with an imaginary JavaScript server:
import { renderToString } from 'react-dom/server'
import { match, RouterContext } from 'react-router'
import routes from './routes'
serve((req, res) => {
// Note that req.url here should be the full URL path from
// the original request, including the query string.
match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message)
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
res.status(200).send(renderToString(<RouterContext {...renderProps} />))
} else {
res.status(404).send('Not found')
}
})
})
For data loading, you can use the renderProps
argument to build whatever convention you want--like adding static load
methods to your route components, or putting data loading functions on the routes--it's up to you.