apollographql / apollographql/apollo-client-integrations

Proper way to use with Next SSR caching - Always seeing loading state / data not caching

Open
#291 6 comments 2 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
556
Forks
53
PR merge metrics
No merged PRs in 30d

Description

Hi, first of all thanks for this amazing library.

I'm trying to figure out the proper use for rendering & caching with SSR/Next. I'm using `fetchOptions: { cache: 'force-cache' }` in the SSR Apollo Wrapper. However I'm still seeing my graphql server being hit for every request, and it always shows the loading page for a second or if i disable JS (testing on the deploy).

Folder structure:
```
- app/blog/[id]/page.tsx
- server component (no 'use client')
- uses an apollo RSC client here for generateMetadata (no fetchOptions defined)
- return
- export const revalidate = 86400;

- app/blog/[id]/loading.tsx
- server component
- loading screen

- app/blog/[id]/BlogPage.tsx
- client component 'use client'
- const { data } = useSuspenseQuery(GetGuideDocument, {
variables: {
guideId,
},
fetchPolicy: 'cache-and-network',
context: {
fetchOptions: {
cache: 'force-cache',
},
},
});
```

Full SSR:
```tsx
'use client';
declare module '@apollo/client' {
export interface DefaultContext {
token?: string;
}
}

import { ApolloLink, HttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import {
ApolloNextAppProvider,
NextSSRInMemoryCache,
NextSSRApolloClient,
SSRMultipartLink,
} from '@apollo/experimental-nextjs-app-support/ssr';
import typePolicies from './typePolicies';

const uri = `${process.env.NEXT_PUBLIC_GRAPHQL_URL}/graphql`;

// have a function to create a client for you
function makeClient() {
const authLink = setContext(async (_, { headers, token }) => {
return {
headers: {
...headers,
...(token ? { authorization: `Bearer ${token}` } : {}),
},
};
});

const httpLink = new HttpLink({
// this needs to be an absolute url, as relative urls cannot be used in SSR
uri,
// you can disable result caching here if you want to
// (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
fetchOptions: { cache: 'force-cache' },
});

return new NextSSRApolloClient({
cache: new NextSSRInMemoryCache({
typePolicies,
}),
link:
typeof window === 'undefined'
? ApolloLink.from([
new SSRMultipartLink({
stripDefer: true,
}),
authLink.concat(httpLink),
])
: authLink.concat(httpLink),
});
}

// you need to create a component to wrap your app in
export function ApolloWrapper({ children }: React.PropsWithChildren) {
return (

{children}

);
}
```

Full RSC
```ts
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { registerApolloClient } from '@apollo/experimental-nextjs-app-support/rsc';

const { getClient } = registerApolloClient(() => {
return new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: process.env.NEXT_PUBLIC_GRAPHQL_URL + '/graphql',
// you can disable result caching here if you want to
// (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
// fetchOptions: { cache: "no-store" },
}),
});
});

export default getClient;
```

Thanks, any help much appreciated.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reproducing the request flow in app/blog/[id]/page.tsx, app/blog/[id]/BlogPage.tsx, and app/blog/[id]/loading.tsx, then inspect the ApolloWrapper and RSC client configurations shown in the report. Verify whether the SSR requests are cached and why the loading state appears; done means documenting the required configuration or confirming a library issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, next.js, typescript
Domain
api, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.