apollographql / apollographql/apollo-client-integrations
Proper way to use with Next SSR caching - Always seeing loading state / data not caching
- 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