0

Im testing react-query and SSR from nextjs to prefetch data only when the staleTime is gone. But after testing it, every 20 seconds a new get request is done to the API, even if the the staleTime is more than 20 seconds. I don't really understand why. This is the code:

Index:

import { dehydrate, QueryClient, useQuery } from "@tanstack/react-query";
import Image from "next/image";
import axios from "axios";

type SpaceXData = {
  name: string;
  links: {
    patch: {
      large: string;
    };
  };
};

const getSpaceXData = async () =>
  await (
    await axios("https://api.spacexdata.com/v4/launches/latest")
  ).data;

export default function Page() {
  const { data } = useQuery<SpaceXData>(["spacex"], getSpaceXData);

  console.log(data);

  if (!data) return <h1>Error</h1>;

  return (
    <div>
      <h1>{data.name}</h1>
      <Image
        src={data.links.patch.large}
        alt="image"
        width={500}
        height={500}
      />
    </div>
  );
}

export async function getStaticProps() {
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery(["spacex"], getSpaceXData, {
    staleTime: 30000,
  });

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}

_app.tsx:

import "tailwindcss/tailwind.css";

import type { AppProps } from "next/app";
import {
  QueryClient,
  QueryClientProvider,
  Hydrate,
} from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import React from "react";

function App({ Component, pageProps }: AppProps) {
  const queryClient = React.useRef(
    new QueryClient({
      defaultOptions: {
        queries: {
          refetchOnWindowFocus: false,
          retry: false, staleTime: 30000,

        },
      },
    })
  );

  return (
    <QueryClientProvider client={queryClient.current}>
      <Hydrate state={pageProps.dehydratedState}>
        <Component {...pageProps} />
      </Hydrate>
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}
export default App;

With react-query devtools I can see that the data only becomes stales after 30 seconds, but in between those 30 seconds a request is done and the other are all cache requests. I have tried to put a timeout on the axios request but the behaviour is the same. Maybe its because I have two query-clients or maybe is the SSR from next that is doing the revalidation.

1 Answers1

0

Let me know if I'm misunderstanding the Question, but it sounds like you're seeing the fetches on the server, when you navigate between pages? Note that getStaticProps is called for every request in development mode.

With server side rendering, we have to distinguish between two scenarios:

  1. a fetch happens on the server. This is your getStaticProps.
  2. a fetch happens on the client. This would be re-fetches triggered by react-query, or because a new useQuery instance mounts etc.

The QueryCache lives inside the QueryClient, which is why you create one in an instance ref in your _app.tsx. This QueryClient will be available on the client / browser - only for scenario 2)

This is also the QueryClient that gets data hydrated from the server when the page first renders.

But on the server, inside getStaticProps, the queryClient is newly created every time:

const queryClient = new QueryClient();

await queryClient.prefetchQuery(["spacex"], getSpaceXData, {
  staleTime: 30000,
});

this means when you make that prefetch, the cache inside that client is empty (so putting staleTime there doesn't achieve much).

So, what you would need to de-duplicate those requests as well is some sort of server-side caching. If you put the queryClient outside of getStaticProps, it would live in-memory on the server, but data would be shared between all users, which is why it's not encouraged. Server-side caching is a completely different sort of caching, you could think about storing the result of the QueryClient in redis and re-using it, but it's usually not worth it. Especially because getStaticProps is only called on every request in dev mode, not in production. This is more of a getServerSideProps problem.

TkDodo
  • 20,449
  • 3
  • 50
  • 65