Start by checking You might not need React Router article by Konstantin Tarkus
It shows how to implement Router.resolve(routes, context)
method with just a few lines of code,
which in combination with history
npm module (handles client-side navigation) can be a good
routing solution for many React applications.
This article demonstrates imperative (functional) routes. But if you're planning to use Relay, it
might be a better idea to use declarative routes instead. For example, you can declare all routes
for your React application in a single routes.json
file that may look like this:
[
{
"path": "/tasks",
"component": "./views/tasks/TodoList",
"queries": {
"viewer": "query { viewer }",
"tasks": "query { tasks }"
}
},
{
"path": "/tasks/:id(\\d+)",
"component": "./views/tasks/TodoItem",
"queries": {
"viewer": "query { viewer }",
"tasks": "query { task(id: $id) }"
}
}
]
And convert that into JavaScript array at compile time by using routes loader for Webpack. So, after this JSON code is transformed by routes-loader, it may look as follows:
import Relay, { RelayRenderer } from 'react-relay';
module.exports = [
{
path: "/tasks",
queries: {
viewer: () => Relay.QL`query { viewer }`,
tasks: () => Relay.QL`query { tasks }`
},
async action({ params }) {
const [Component, props ] = await Promise.all([
System.import('./views/tasks/TodoItem')},
Object.keys(this.queries).map(x => this.queries[key]).map(...) // TODO: Fetch data
]);
return <Component {...props} />;
}
},
{
path: '/tasks/:id(\\d+)',
queries: {
viewer: () => Relay.QL`query { viewer }`,
tasks: () => Relay.QL`query { task(id: $id) }`
},
async action({ params }) {
const [Component, ...data ] = await Promise.all([
System.import('./views/tasks/TodoItem')},
...Object.keys(this.queries).map(key => new Promise(resolve => {
const query = Relay.createQuery(this.queries[key], params);
Relay.Store.primeCache({ query: query }, readyState => {
if (readyState.done) {
resolve(Relay.Store.readQuery(query)[0])
}
});
}));
Object.keys(this.queries).map(x => this.queries[key]).map(...) // TODO: Fetch data
]);
return <Component {...Object.keys(this.queries).reduce((o, k, i) => { o[k] = data[i]; }, {})} />;
}
}
];
Note: This is just a rough example, needs to be cleand up / refactored for production use.
Then you can use these routes as usual:
import Router from 'universal-router'; // or, a custom resolve() functions
import routes from './routes.json'; // Transformed with utils/routes-loader.js
Router.resolve(routes, { path: '/tasks/123' }).then(component => ReactDOM.render(component, container));
You can find an example of this routing approach in React Static Boilerplate
project. That one uses whatwg-fetch
for data fetching, but it can be easily replaced with Relay.