为什么我在Next.js中使用tanstack/react-query的React查询仍然在staleTime结束之前发出API请求?

vsdwdz23  于 2023-05-28  发布在  React
关注(0)|答案(1)|浏览(212)

我测试react-query和SSR从nextjs预取数据只有当staleTime过去了。但是在测试之后,每20秒都会向API发出一个新的get请求,即使staleTime超过20秒。我真的不明白为什么这就是代码:

索引

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;

使用react-query devtools,我可以看到数据只有在30秒后才会过期,但在这30秒之间,一个请求完成,其他都是缓存请求。我尝试在axios请求上设置超时,但行为是相同的。也许是因为我有两个查询客户端,或者可能是下一个SSR正在进行重新验证。

pvabu6sv

pvabu6sv1#

如果我误解了这个问题,请告诉我,但是当你在页面之间导航时,听起来你看到的是服务器上的抓取?注意,在开发模式下,每个请求都会调用getStaticProps
对于服务器端渲染,我们必须区分两种场景:
1.在服务器上发生获取。这是你的getStaticProps
1.在客户端上发生获取。这可能是由react-query触发的重新获取,或者因为新的useQuery示例挂载等。
QueryCache位于QueryClient内部,这就是为什么要在_app.tsx的示例引用中创建一个QueryCache的原因。此QueryClient将在客户端/浏览器上可用-仅适用于场景2)
这也是QueryClient,当页面第一次呈现时,它从服务器获取数据水合
但是在服务器上,在getStaticProps内部,每次都新创建queryClient:

const queryClient = new QueryClient();

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

这意味着当您进行预取时,客户端内部该高速缓存是空的(因此将staleTime放在那里并没有实现太多)。
因此,您还需要对这些请求进行重复数据删除,这是某种服务器端缓存。如果您将queryClient放在getStaticProps之外,它将位于服务器的内存中,但数据将在所有用户之间共享,这就是为什么不鼓励这样做的原因。服务器端缓存是一种完全不同的缓存,你可以考虑将QueryClient的结果存储在redis中并重用它,但这通常不值得。特别是因为getStaticProps只在开发模式下对每个请求调用,而不是在生产模式下。这更像是一个getServerSideProps问题。

相关问题