Apollo provides two techniques to allow your applications to load quickly, avoiding unnecessary delays to users:
- Store rehydration, which allows your initial set of queries to return data immediately without a server roundtrip.
- Server side rendering, which renders the initial HTML view on the server before sending it to the client.
You can use one or both of these techniques to provide a better user experience.
For applications that can perform some queries on the server prior to rendering the UI on the client, Apollo allows for setting the initial state of data. This is sometimes called rehydration, since the data is “dehydrated” when it is serialized and included in the initial HTML payload.
For example, a typical approach is to include a script tag that looks something like:
You can then rehydrate the client using the initial state passed from the server:
We’ll see below how you can generate both the HTML and the Apollo store’s state using Node and
react-apollo‘s server rendering functions. However if you are rendering HTML via some other means, you will have to generate the state manually.
Then, when the client runs the first set of queries, the data will be returned instantly because it is already in the store!
If you are using
forceFetch on some of the initial queries, you can pass the
ssrForceFetchDelay option to skip force fetching during initialization, so that even those queries run using the cache:
You can render your entire React-based Apollo application on a Node server using rendering functions built into
react-apollo. These functions take care of the job of fetching all queries that are required to rendering your component tree. Typically you would use these functions from within a HTTP server such as Express.
No changes are required to client queries to support this, so your Apollo-based React UI should support SSR out of the box.
In order to render your application on the server, you need to handle a HTTP request (using a server like Express, and a server-capable Router like React-Router), and then render your application to a string to pass back on the response.
We’ll see how to take your component tree and turn it into a string in the next section, but you’ll need to be a little careful in how you construct your Apollo Client instance on the server to ensure everything works there as well:
When creating an Apollo Client instance on the server, you’ll need to set up you network interface to connect to the API server correctly. This might look different to how you do it on the client, since you’ll probably have to use an absolute URL to the server if you were using a relative URL on the client.
Since you only want to fetch each query result once, pass the
ssrMode: trueoption to the Apollo Client constructor to avoid repeated force-fetching.
You need to ensure that you create a new client or store instance for each request, rather than re-using the same client for multiple requests. Otherwise the UI will be getting stale data and you’ll have problems with authentication.
Once you put that all together, you’ll end up with initialization code that looks like this:
You can check out the GitHunt app’s
ui/server.js for a complete working example.
Next we’ll see what that rendering code actually does.
getDataFromTree function takes your React tree, determines which queries are needed to render them, and then fetches them all. It does this recursively down the whole tree if you have nested queries. It returns a promise which resolves when the data is ready in your Apollo Client store.
At the point that the promise resolves, your Apollo Client store will be completely initialized, which should mean your app will now render instantly (since all queries are prefetched) and you can return the stringified results in the response:
Your markup in this case can look something like:
Avoiding the network for local queries
If your GraphQL endpoint is on the same server that you’re rendering from, you may want to avoid using the network when making your SSR queries. In particular, if localhost is firewalled on your production environment (eg. Heroku), making network requests for these queries will not work. One solution to this problem is the apollo-local-query module, which lets you create a
networkInterface for apollo that doesn’t actually use the network.
Skipping queries for SSR
If you want to intentionally skip a query during SSR, you can pass
ssr: false in the query options. Typically, this will mean the component will get rendered in its loading state on the server. For example:
renderToStringWithData function simplifies the above and simply returns the content string that you need to render. So it reduces the number of steps slightly: