React Apollo SSR getDataFromTree not waiting for query

Viewed 1903

I'm trying to set up SSR for my React app, which uses Apollo Client for graphql requests to an API. I've set up the webpack config, and the Express app, correctly, and I can see the components getting loaded. The issue here is that getDataFromTree is not waiting for my query at all. It simply returns the component with loading: true and then nothing. I set ssrForceFetchDelay as well to make the client refetch the queries, but nothing.

I keep getting window.__APOLLO_STATE__={}. The components are very basic, making simple queries and displaying the result.

This is my express app:

    app.use((req, res) => {
     const client = new ApolloClient({
     ssrMode: true,
     link: new HttpLink({
      uri: 'http://localhost:8000/graphql',
      fetch: fetch
     }),
     cache: new InMemoryCache(),
    });
    const app = (
     <ApolloProvider client={client}>
      <Router location={req.url} context={{}}>
        <App client={client}/>
      </Router>
     </ApolloProvider>
    );
   const jsx = extractor.collectChunks(app); // Using loadable

   renderToStringWithData(jsx).then((dataResp) => {   
    const content = dataResp;   
    const state = client.extract(); // Always {}
    const helmet = Helmet.renderStatic();
    const html = ReactDOMServer.renderToStaticMarkup(
      <Html content={content} helmet={helmet} assets={assets} state={state} />,
    );
    res.status(200); res.send(`<!doctype html>${html}`);
    res.end();
    }).catch(err => {
     console.log(`Error thrown`);
    }); 
   });

   app.listen(port, () => {
    console.log(`Server listening on ${port} port`);
   });

This is my client-side Apollo config:

const cache = new InMemoryCache().restore(window.__APOLLO_STATE__);
const client = new ApolloClient({
  ssrForceFetchDelay: 300,
  link: links,
  cache: cache,
  connectToDevTools: true,
});

My App :

const Wrapped = () => {
    console.log(`Inside Wrapped`);
    return (
    <ApolloProvider client={apolloClient}> //The client one
        <Router>
            <App />  /*Only returns 2 basic components */
        </Router>
      </ApolloProvider>
    );
  };

  hydrate(<Wrapped />, document.getElementById('root'));

I can see the components on the page, but no queries have been loaded and APOLLO_STATE is always empty. I've been following the documentation on react-apollo to set this up, but I can't understand why this basic set up won't work. Any ideas on what I need to change here? Thanks!

Html component:

import React from 'react';

const Html = ({ content, helmet, assets, state }) => {
  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no"
        />
        <meta name="theme-color" content="#000000" />
        <link rel="manifest" href="/manifest.json" />
        <link rel="shortcut icon" href="/favicon.ico" />
        {helmet.meta.toComponent()}
        {helmet.title.toComponent()}
        {assets.css &&
          assets.css.map((c, idx) => (
            <link key={idx} href={c} rel="stylesheet" />
          ))}
      </head>

      <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <div id="root" dangerouslySetInnerHTML={{ __html: content }} />
        <script
          dangerouslySetInnerHTML={{
            __html: `window.__APOLLO_STATE__=${JSON.stringify(state).replace(
              /</g,
              '\\u003c',
            )};`,
          }}
        />
        {assets.js &&
          assets.js.map((j, idx) => (
            <script key={idx} src={j} />
          ))}
      </body>
    </html>
  );
};

export default Html;

EDIT: Added my HTML component code

Link to repo with basic code that is working correctly. I intend to add Loadable to this to see if that is what is causing the issue.

https://github.com/kvnam/gql-ssr-test

0 Answers
Related