6

Edit: is this not working because I'm not calling getInitialProps? NextJS documentation (https://nextjs.org/docs/basic-features/data-fetching#server-side-rendering) says that if you don't then the page is statically rendered at build time. So I should put my useQuery inside getInitialProps?

I'm testing out an Apollo Client front end that connects through GraphQL to a KeystoneJS CMS backend. One method of testing whether SSR is working is, as I understand it, to load a page in a browser, check the source and see if the HTML is in there. It's not working for me.

The page source is as follows (it's ugly, I'm just testing out that connections and SSR work):

import React from 'react';
import Head from 'next/head';
import {useQuery} from '@apollo/react-hooks';
import gql from 'graphql-tag';

const ARTICLES_QUERY = gql`
  query {

   allArticles {
      title
      text
  }
  }
`;

const Home = () => {
    // Create a query hook
    const {data, loading, error} = useQuery(ARTICLES_QUERY);
  console.log(data)
    if (loading) {
        return <p>Loading...</p>;
    }

    if (error) {
        return <p>Error: {JSON.stringify(error)}</p>;
    }
    return (
        <div>
            <Head>
                <title>Home</title>
                <link rel="icon" href="/favicon.ico"/>
            </Head>
            <p>some paragraph text</p>
            <div>And something in a div</div>
            <ul>
                {data?.allArticles?.map(article => {
                    return <li key={`article__${article.title}`}>{article.title}</li>;
                })}
            </ul>
        </div>
    );
};

export default Home;

The page renders as

enter image description here

and the page source for that page is

<!DOCTYPE html><html><head><style data-next-hide-fouc="true">body{display:none}</style><noscript data-next-hide-fouc="true"><style>body{display:block}</style></noscript><meta charSet="utf-8"/><meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/development/pages/index.js?ts=1582296618319" as="script"/><link rel="preload" href="/_next/static/development/pages/_app.js?ts=1582296618319" as="script"/><link rel="preload" href="/_next/static/runtime/webpack.js?ts=1582296618319" as="script"/><link rel="preload" href="/_next/static/runtime/main.js?ts=1582296618319" as="script"/><noscript id="__next_css__DO_NOT_USE__"></noscript></head><body><div id="__next"><p>Loading...</p></div><script src="/_next/static/development/dll/dll_d6a88dbe3071bd165157.js?ts=1582296618319"></script><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{},"apolloState":{},"apollo":null},"page":"/","query":{},"buildId":"development","isFallback":false}</script><script nomodule="" src="/_next/static/runtime/polyfills.js?ts=1582296618319"></script><script async="" data-next-page="/" src="/_next/static/development/pages/index.js?ts=1582296618319"></script><script async="" data-next-page="/_app" src="/_next/static/development/pages/_app.js?ts=1582296618319"></script><script src="/_next/static/runtime/webpack.js?ts=1582296618319" async=""></script><script src="/_next/static/runtime/main.js?ts=1582296618319" async=""></script><script src="/_next/static/development/_buildManifest.js?ts=1582296618319" async=""></script></body></html>

Neither my static HTML nor the dynamic content is in there.

I am missing something obvious here? Is it the Apollo Client cache? Is it something I'm missing about how NextJS should work? This is all on first page load -- that is, I know it's client-side rendered when you navigate on client side, but this should come straight from the server, no?

For what it's worth, pages/_app.js is

import React from 'react';
import App from 'next/app';
import { ApolloProvider } from '@apollo/react-hooks';

import withData from '../util/apollo-client';

class MyApp extends App {
    render() {
        const { Component, pageProps, apollo } = this.props;
        return (
            <ApolloProvider client={apollo}>
                <Component {...pageProps} />
            </ApolloProvider>
        );
    }
}

// Wraps all components in the tree with the data provider
export default withData(MyApp)

and /util/apollo-client.jsis

import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import withApollo from 'next-with-apollo';
import { createHttpLink } from 'apollo-link-http';
import fetch from 'isomorphic-unfetch';

// Update the GraphQL endpoint to any instance of GraphQL that you like
const GRAPHQL_URL = 'http://localhost:3000/admin/api';

const link = createHttpLink({
    fetch, // Switches between unfetch & node-fetch for client & server.
    uri: GRAPHQL_URL
});

// Export a HOC from next-with-apollo
// Docs: https://www.npmjs.com/package/next-with-apollo
export default withApollo(
    // You can get headers and ctx (context) from the callback params
    // e.g. ({ headers, ctx, initialState })
    ({ initialState }) =>
        new ApolloClient({
            link: link,
            cache: new InMemoryCache()
                //  rehydrate the cache using the initial data passed from the server:
                .restore(initialState || {})
        })
);
1
  • Do you solve the problem? Commented Jun 4, 2020 at 2:25

1 Answer 1

4

I think ApolloClient is missing ssrMode option

Include the option into your withApollo function as follows:

Example:

// Export a HOC from next-with-apollo
// Docs: https://www.npmjs.com/package/next-with-apollo
export default withApollo(
    // You can get headers and ctx (context) from the callback params
    // e.g. ({ headers, ctx, initialState })
    ({ initialState, ctx }) =>
        new ApolloClient({
            ssrMode: Boolean(ctx),
            link: link,
            cache: new InMemoryCache()
                //  rehydrate the cache using the initial data passed from the server:
                .restore(initialState || {})
        })
);
Sign up to request clarification or add additional context in comments.

2 Comments

I'll try that. I was able to get it to work without adding ssrMode by adding getInitialProps to both _app.js and my page. I read from the docs about ssrMode (apollographql.com/docs/react/performance/server-side-rendering), "Since you only want to fetch each query result once, pass the ssrMode: true option to the Apollo Client constructor to avoid repeated force-fetching." -- But is the client always on the server? When NextJS moves to renders locally, does it move the client there? How does it all work?
Hey @Cerulean do you have an example of this in both the _app.js page and your other page?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.