Next.js: Error with Apollo data fetching and Next 9

Created on 8 Aug 2019  ·  11Comments  ·  Source: vercel/next.js

Bug report

Describe the bug

After upgrading to Next 9, I've encountered an issue when I am trying to use Apollo together with getInitialProps on client-side as well (e.g. condition on this line is removed).

When clicking between pages, which are trying to fetch data inside getInitialProps an error: Error while running getDataFromTree Invariant Violation: ReactDOMServer does not yet support Suspense. occurs.

image

To Reproduce

Repo: https://github.com/prichodko/next-with-apollo-issue

  1. Start app
  2. Open console and click between pages

Expected behavior

Fetch data without the error.

System information

  • OS: macOS
  • Version of Next.js: latest

I am not 100% sure if it's a Next or Apollo's issue. But since it was working with Next 8 I opened it here. I am happy to try to help with the issue.

needs investigation

Most helpful comment

Hi @Timer, I'm looking at the commits of with-apollo example but cannot find the update you are referencing https://github.com/zeit/next.js/commits/canary/examples/with-apollo ?

All 11 comments

@prichodko Right, the implementation of getDataFromTree changed and trying to run it in the browser ends up with that error, I don't think it's intended to be used in the browser and I also don't see any reasons to do it. Try opening up an issue in react-apollo instead if you need this.

Actually I'm wrong, I thought this was related to the latest release of Apollo with hooks which also has this error but you're using the old version, I'm going to investigate 👌

@lfades

I also don't see any reasons to do it.

I want to leverage getInitialProps and fetch data before routing to different page. Is there any other way to fetch queries and avoid loaders?

Basically I want achieve this, but with new @apollo/react-hooks. However it seems to be an issue with the new @apollo/react-ssr package.

I'm solving prefetching during client-side navigation roughly like this:

// in lib/preloadGraphqlQuery
export const preloadGraphqlQuery = async (apolloClient, options) => {
  if (typeof window !== "undefined") {
    try {
      await apolloClient.query(options);
    } catch (e) {
      // noop
    }
  }
};

// in pages/my-page
import { preloadGraphqlQuery } from "../lib/preloadGraphqlQuery";

export const Query1 = gql`...`;
export const Query2 = gql`...`;

const MyPage = () => {
  const result1 = useQuery(Query1);
  const result2 = useQuery(Query2);

  return <>...</>;
};

MyPage.getInitialProps = async ({ query, apolloClient }) => {
  await Promise.all([
    preloadGraphqlQuery(apolloClient, { query: Query1 }),
    preloadGraphqlQuery(apolloClient, { query: Query2 }),
    // ↑ I can choose which queries get preloaded before navigation finishes and for which it is fine to show a loader later
  ]);
};

In order to make apolloClient available inside getInitialProps, I had to add ctx.ctx.apolloClient = apollo; after https://github.com/zeit/next.js/blob/0e01435f648d266198ed5de0a64ca1603f76c5a0/examples/with-apollo/lib/with-apollo-client.js#L19

Maybe it's not the most beautiful solution, but it seems to work 🤷‍♂️

Thanks for sharing your solution 👍

However it seems quite a lot of work for something which was and could work out of the box (also when react-apollo has a built in flag for skipping SSR - docs).

Getting this error on next 9.0.5 and other versions 9.x.x

Error while running `getDataFromTree` TypeError: Class constructor App cannot be invoked without 'new'
TypeError: Class constructor Document cannot be invoked without 'new'

I get the Invariant error on 9.0.1 but it doesn't give me an internal server error like > 9.0.1
On 9.0.1 the page gets rendered

After some more investigation, I think this is an issue with Apollo itself.

  1. I've used the getMarkupFromTree() function to customize the renderFunction in order to make it run on the browser without throwing errors:
// Run all GraphQL queries
const tree = React.createElement(AppTree as any, {
  ...appProps,
  apolloClient: apollo,
});

if (isBrowser) {
  console.log('bsr');
  await getMarkupFromTree({
    tree,
    renderFunction: data => {
      const tempDiv = document.createElement('div');
      render(data, tempDiv);
      return tempDiv.innerHTML;
    },
  });
  console.log('afterLoad?');
} else {
  console.log('ssr');
  await getDataFromTree(tree);
}
  1. So now it runs on the browser, but this issue is that the promises with GraphqQL queries are not resolved (still investigating https://github.com/apollographql/react-apollo/blob/master/packages/hooks/src/ssr/RenderPromises.ts to find the culprit)

With a breakpoint on console.log('afterLoad?'); I can see that no requests where triggered yet, but this might because of using ReactDOM.render instead of ReactDOM.renderToStaticMarkup

Since getDataFromTree uses ReactDOMServer.renderToStaticMarkup and NextJS has some code-splitting on the browser side, getDataFromTree cannot work on the browser in this state.

Thanks @iam4x. Is there bug/issue (or plan to file) in @apollo/react-hooks ?

@ceefour yes, there's an issue open on react-apollo here: https://github.com/apollographql/react-apollo/issues/3511

Closing as we've comprehensively updated our Apollo examples.

Hi @Timer, I'm looking at the commits of with-apollo example but cannot find the update you are referencing https://github.com/zeit/next.js/commits/canary/examples/with-apollo ?

Was this page helpful?
0 / 5 - 0 ratings