I build apps and websites, and lately I’ve been building isomorphic/universal websites with React. This is how you can use React Router to render on the server with Koa.
The basics are straightforward:
If you’ve got an error or a redirect you can use Koa’s this.throw and this.redirect, and if you’ve got nothing you can throw a 404. On the other hand, if you’ve got renderProps you can then pass React Router’s <RouterContext {…renderProps} /> to react-dom/server’s renderToStringfunction.
require('babel-core/register');
var ReactDOMServer = require('react-dom/server');
var ReactRouter = require('react-router');
var koa = require('koa');
var render = require('koa-ejs');
var path = require('path');
var RouterContext = require('./RouterContext');
var App = require('./components/App');
var app = koa();
render(app, {root: path.join(__dirname, 'view')});
app.use(function *() {
const routes = {
path: '/',
component: App
};
ReactRouter.match({
routes: routes,
location: this.url
}, (error, redirectLocation, renderProps) => {
if (error) {
this.throw(error.message, 500);
} else if (redirectLocation) {
this.redirect(redirectLocation.pathname + redirectLocation.search);
} else if (renderProps) {
var reactString = ReactDOMServer.renderToString(RouterContext(renderProps));
this.render('layout', {react: reactString});
} else {
this.throw('Not Found', 404);
}
});
});
var port = process.env.PORT || 3000;
app.listen(port);
});
A couple of things thrown in there:
My RouterContext.jsx looks like:
var React = require('react');
var RoutingContext = require('react-router').RoutingContext;
module.exports = (renderProps) => <RoutingContext {…renderProps} />;
This is because the current version of React Router provides RoutingContext which has since been renamed to RouterContext (which is what the docs talk about).