apollographql / apollo-client-nextjs

Apollo Client support for the Next.js App Router
https://www.npmjs.com/package/@apollo/experimental-nextjs-app-support
MIT License
358 stars 25 forks source link

How to get the latest data #200

Open bingjian1819 opened 2 months ago

bingjian1819 commented 2 months ago
import { HttpLink } from '@apollo/client';
import { registerApolloClient } from '@apollo/experimental-nextjs-app-support/rsc';
import {
  NextSSRApolloClient,
  NextSSRInMemoryCache,
} from '@apollo/experimental-nextjs-app-support/ssr';

import { APOLLO_CLIENT_URL } from './apolloClient';

export const { getClient } = registerApolloClient(() => {
  return new NextSSRApolloClient({
    cache: new NextSSRInMemoryCache(),
    link: new HttpLink({
      uri: APOLLO_CLIENT_URL,
      fetchOptions: { cache: 'no-store' },
    }),
  });
});
export default async function Index() {
  const { data } = await getClient().query({
    query: queryImages,
    variables: { limit: LIMIT_IMAGES_COUNT, offset: 0 },
    context: {
      fetchOptions: {
        next: { revalidate: 10 },
      },
    },
    fetchPolicy: 'no-cache',
  });

  return (
    <div className={'min-h-full w-full'}>
      <PageContent initData={data.images} />
    </div>
  );
}

The backend data is updated frequently, but the data I get every time is only the data from the last build. I've tried without caching without success.

phryneas commented 2 months ago

This looks to me like for some reason, Next.js is caching your network requests.

The code you share here looks like you are opting out of it, but at the same time, it seems like it doesn't.

In React Server components, getClient creates a new Apollo Client instance for each new incoming request, so it can't be on the Apollo Client side.

One thought, though:

You should be using the normal ApolloClient here, not the SSRClient. You are in a RSC environment, that has nothing to do with SSR.

export const { getClient } = registerApolloClient(() => {
-  return new NextSSRApolloClient({
+  return new ApolloClient({
-    cache: new NextSSRInMemoryCache(),
+    cache: new InMemoryCache(),
    link: new HttpLink({
      uri: APOLLO_CLIENT_URL,
      fetchOptions: { cache: 'no-store' },
    }),
  });
});
bingjian1819 commented 2 months ago

@phryneas Thank you for the reply

After I updated it according to your suggestion, I still can't get the latest data.

phryneas commented 2 months ago

Then at some point, Next.js seems to be caching network requests - see my link above. getClient will always give you a new, empty Apollo Client for every incoming network request, so there is no data that we could even cache.

luchillo17 commented 2 months ago

Am I missing the point here? I thought the registerApolloClient would cache the client, so the getClient would give you the same instance of that client, especially because getClient doesn't receive any params, so I expected to always get the same client instance since there will never exist a cache miss for React's cache.

https://github.com/apollographql/apollo-client-nextjs/blob/main/packages/client-react-streaming/src/registerApolloClient.tsx#L5

kierangillen commented 2 months ago

I'm also having this same issue, the data is stale unless the site is rebuilt by vercel.

kierangillen commented 2 months ago

My query looks like:

  const { data } = await getClient().query({
    query: HomeQuery,
    fetchPolicy: "no-cache",
  });

And my Apollo client instance is:

import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";
import { registerApolloClient } from "@apollo/experimental-nextjs-app-support/rsc";

export const { getClient } = registerApolloClient(() => {
  return new ApolloClient({
    cache: new InMemoryCache(),
    link: new HttpLink({
      uri: process.env.NEXT_PUBLIC_SANITY_ENDPOINT,
    }),
  });
});
luchillo17 commented 2 months ago

@kierangillen What does your component/page look like? it might have to do with https://nextjs.org/docs/app/building-your-application/caching#on-demand-revalidation

Specifically the option dynamic, might help:

// Opt out of caching for all data requests in the route segment
export const dynamic = 'force-dynamic'

There's also a mention about Vercel's Data Cache right below that section that links to this, take a look it might help with your issue specifically: https://vercel.com/docs/infrastructure/data-cache

kierangillen commented 2 months ago

Thanks @luchillo17.

I ended up adding export const revalidate = 60; to my layout.tsx and it solved the issue.

phryneas commented 2 months ago

Am I missing the point here? I thought the registerApolloClient would cache the client, so the getClient would give you the same instance of that client, especially because getClient doesn't receive any params, so I expected to always get the same client instance since there will never exist a cache miss for React's cache.

Yes and no :)

The point of registerApolloClient is that if you call getClient a dozen times during handling a single request, you get the same Apollo Client instance everywhere - so you don't have to pass it around through props inside of your application.

But if you call getClient from two different requests, you should always get two distinct ApolloClient instances, as we can't risk "mixing data" between requests - it could be private data for different authenticated users.

luchillo17 commented 2 months ago

Gotcha, @kierangillen's got a fix, now we wait for @bingjian1819 feedback.

lablancas commented 2 months ago

Thanks @luchillo17.

I ended up adding export const revalidate = 60; to my layout.tsx and it solved the issue.

Hi @kierangillen ... i am dealing with similar issues I think. Is your current code something available on Github to review? I am setting revalidate in my page.tsx ... did. you try that? Did that not help? Wondering if I should move it to layout.tsx... also, wondering if there is anything else in your code that might be different from mine?

kierangillen commented 2 months ago

@lablancas hey sorry the repo I was working in is private. I'd suggest putting in the layout.tsx and see if that helps.