Adds server side rendering support to React Relay.
If you are using react-router-relay, then you might also be interested in isomorphic-relay-router, which uses isomorphic-relay.
Thanks to @voideanvalue for the information that helped create the initial version this project. I also thanks @josephsavona for valuable advices that helped improve it.
npm install -S isomorphic-relay
Make sure isomorphic-relay module is loaded before react-relay on the server, because isomorphic-relay includes a hack to prevent "self is not defined" error (see facebook/fbjs#47):
// First load isomorphic-relay:
import IsomorphicRelay from 'isomorphic-relay';
// And only then load react-relay:
import Relay from 'react-relay';
Don't forget to inject a network layer to Relay on the server.
And if you are using Relay.DefaultNetworkLayer
, specify the full url to the GraphQL endpoint:
const GRAPHQL_URL = `http://localhost:8080/graphql`;
Relay.injectNetworkLayer(new Relay.DefaultNetworkLayer(GRAPHQL_URL));
Inject a no-op batching strategy into the Relay change emitter, but only on the server:
import RelayStoreData from 'react-relay/lib/RelayStoreData';
RelayStoreData.getDefaultInstance().getChangeEmitter().injectBatchingStrategy(() => {});
When processing a request on the server, prepare the data using IsomorphicRelay.prepareData
,
then render React using IsomorphicRelay.RootContainer
in place of Relay.RootContainer
,
and send the React output along with the data to the client:
app.get('/', (req, res, next) => {
const rootContainerProps = {
Component: MyContainer,
route: new MyRoute(),
};
IsomorphicRelay.prepareData(rootContainerProps).then(data => {
const reactOutput = ReactDOMServer.renderToString(
<IsomorphicRelay.RootContainer {...rootContainerProps} />
);
res.render('index.ejs', {
preloadedData: JSON.stringify(data),
reactOutput
});
}, next);
});
On page load in the browser, inject the prepared data to the Relay store
using IsomorphicRelay.injectPreparedData
, then render React using IsomorphicRelay.RootContainer
in place of Relay.RootContainer
:
const data = JSON.parse(document.getElementById('preloadedData').textContent);
IsomorphicRelay.injectPreparedData(data);
const rootElement = document.getElementById('root');
// use the same rootContainerProps as on the server
ReactDOM.render(<IsomorphicRelay.RootContainer {...rootContainerProps} />, rootElement);
See here.