denvned/isomorphic-relay

How to load data for a RootContainer supplied to Router on server side?

sidutta opened this issue · 6 comments

I pass a RootContainer with a Relay.Route supplied to it in the isomorphic-relay-router. This root container contains other RootContainers with different Relay.Routes in the component supplied to it. For a complete server side rendering I would like all the data for the RootContainer supplied to router and RootContainers loaded by the component in the supplied RootContainer to be loaded server side.

I read somewhere in the comments that IsomorphicRelay.Renderer should be used in place of the default Relay.Renderer. I can replace the RootContainers with isomorphic renderers. Will it solve the problem? The renderer needs an environment as argument which is different server and client side. How can I effectively use the same renderer while passing in different environments? The problem is particularly serious on server side. I can't create a global variable. So there should be a way to pass the environment created on renderOnServer.js to the IsomorphicRenderer I use in place of RootContainer. this.context.relay is undefined when passed as environment to the renderer.

Why do you need multiple RootContainers/Renderers in the first place?

Because I don't fetch data for all components from a single viewer query properly traversing the graph. Rather I directly query node for data req of those components by passing the nodeId in the following way:

'use strict';

import Relay, {
  Route,
} from 'react-relay';

export default class xyzRoute extends Route {
  static routeParams = {
    xyzId : ''
  };
  static queries = {
    viewer: (Component) => Relay.QL`query {
      node(id : $xyzId) {
        ${Component.getFragment('viewer')}
      }
    }`
  };
  static routeName = 'xyzRoute';
}

Rather I directly query node for data req of those components by passing the nodeId

But you can do it without multiple RootContainers/Renderers.

Even then, if say I use
<Route path="/" component={HomeScreen} queries={ViewerQueries} prepareParams={(params) => {return {...params}}} >
data is rendered on server. However, if I use
<Route path="/" component={HomeScreenContainer} prepareParams={(params) => {return {...params}}} >
and pass a Route equivalent of ViewerQueries to the container, data is fetched from the client.

So, are you trying to suggest that I should not use containers/ renderers at all apart from one call to IsomorphicRelay.Rederer made in renderOnServer.js?

The reason I use the current pattern is because I dont have to care about the entire graph and keep track of properly calling getFragment amongst parent and children components. I get the flexibility to load containers on demand in any existing component without having to worry about how data will flow down from parents.

So, are you trying to suggest that I should not use containers/ renderers at all apart from one call to IsomorphicRelay.Rederer made in renderOnServer.js?

You should never render Rederer or RootContainer yourself when using isomorphic-relay-router. See the ToDo example in the isomorphic-relay-router repository. Also see the documentation for react-router-relay about how to correctly configure routes.