In Next JS:
- SSR - Server side rendering -
getServerSideProps
- SSG - Static site generated -
getStaticPaths
& getStaticProps
- CSR - Client side rendering - everything else
It is important to note that SSG functions are run server-side.
On the client, you only want to create a single global instance of Apollo Client. Creating multiple instances of Apollo Client will make it challenging to keep things in sync with the client. This difficulty is because the Apollo Cache, Apollo Link, etc., will all be stored in different instances of Apollo Client.
In Next, it is common to place the global instance of Apollo Client on the page _app.js
and use the Apollo Provider. On the other client-side pages, you'd use the useQuery
hook that calls your single global instance.
The server-side (SSR) functions getStaticProps
or getServerSideProps
do not have access to the client instance of Apollo, client instance of Next, or other server-side functions. Because of this, you must define your Apollo connection on every page that uses getStaticPaths
, getStaticProps
, or getServerSideProps
and needs access to the Apollo client or it will not be available to the server-side calls.
Since the first rule of hooks is that they must only be called at the top level (client-side), you cannot use them in server-side functions. No, you cannot run useQuery
in the Next SSR or SSG functions.
The example you provide is keeping the cache in sync and is outdated in how it is defining the client. Here is a simplified example more along the lines of the official docs.
graphqlClient.js
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
// Used server and client side - can't use react hooks
export const graphqlClient = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: 'YOUR_GQL_ENDPOINT',
}),
ssrMode: typeof window === 'undefined',
});
_app.js - a single instance that all client pages use because it wraps the whole app
import graphqlClient from 'my/path/graphqlClient';
const App = ({ Component, pageProps }) => {
const client = graphqlClient();
return (
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
);
};
Every page/component that is client-side that can use the useQuery hook because Apollo Client is wrapping the app in _app.js
Client-side query
import { gql, useQuery } from '@apollo/client';
const About = () => {
const { data } = useQuery(YOUR_QUERY); // uses your single instance defined in _app.js
return (
...
)
}
Every page that uses SSR or SSG functions and needs access to Apollo must instantiate a new instance of Apollo.
SSG
import graphqlClient from 'my/path/graphqlClient';
//does not have access to _app.js or client and must define new Apollo Client instance
export const getStaticProps = async () => {
const client = graphqlClient();//
const { data } = await client.query({query: YOUR_QUERY});
};
export const getStaticPaths = async () => {
const client = graphqlClient();
const { data } = await client.query({query: YOUR_QUERY});
};
SSR
import graphqlClient from 'my/path/graphqlClient';
//does not have access to _app.js or client and must define new Apollo Client instance
export const getServerSideProps = async () => {
const client = graphqlClient();
const { data } = await client.query({query: YOUR_QUERY});
};
Lastly, to simplify things you can use graphql-code-generator to auto-generate Apollo query, mutation, etc. hooks (and types for TS users) as well as server-side compatible query and mutation functions for Next.js.