React-Query+ nextjs使用水合配置为SSR不使用缓存结果,并且必须再次等待再次提取

发布于 2025-01-25 04:08:14 字数 2809 浏览 3 评论 0原文

我正在尝试使用SSR/SSG在NextJS应用程序上使用React-Query,并尝试了很多教程。服用水合配置,因为它似乎比initiaLdata方法更好。

以下React-Query指南: https://react-query.tanstack.com/guides/guides/guides/guides/ssr < /a>您只需在QueryClientProvider水合物组件上包装应用程序,将其传递给每个道具即可。

    const App = ({ Component, pageProps }: AppProps) => {
      const [queryClient] = useState(
        () => new QueryClient({ defaultOptions: { queries: { staleTime: 30 * 1000 } } })
      )

      return (
        <QueryClientProvider client={queryClient}>
          <Hydrate state={pageProps.dehydratedState}>
            <ReactQueryDevtools initialIsOpen={false} />
            <ThemeProvider theme={theme}>
              <CssBaseline />
              <Component {...pageProps} />
            </ThemeProvider>
          </Hydrate>
        </QueryClientProvider>
      )
    }

    export default App

要开始在getserversideprops/getStaticProps上开始使用React-Query获取数据,您只需实例一个新的queryClient QueryClient ,Execute prefetchquery并设置了带有的道具脱水(queryclient)

    export async function getStaticProps() {
      const queryClient = new QueryClient()
      await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)

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

    const Home: NextPage = () => {
      const { data, isLoading } = useQuery<Todo[]>('todos', fetchTodos)
      console.log(isLoading)

      if (isLoading) return <h1>Loading...</h1>

我创建了一个小型API,该API返回与 https://jsonplaceholder.typicode.com/todos 但是,settimeout为3秒。问题是,每次我使用next/link重新加载或从一个页面移动到另一页,加载页面需要3秒钟。这表明未使用反应引起缓存。

尝试将QueryClient实例移动到GetServersideProps之外。

尝试将staletime添加到所有查询中,如我的配置所示。

我发现的唯一解决方案是:

    export const queryClient = new QueryClient()

    export async function getStaticProps() {
      if (!queryClient.getQueryData('todos')) {
        await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)
      }

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

但是没有人在谈论它,感觉就像我做错了。

这是我的网络选项卡当移至另一个页面并在我的staletime config> config and queryclient Instanced Instanced GSSP外的30秒之前返回GSSP: 在此处输入图像描述

I'm trying to use react-query on my nextjs app with SSR/SSG and tried a lot of tutorials. Took hydration config because it seems better than initialData approach.

Following react-query guide: https://react-query.tanstack.com/guides/ssr you just have to wrap the app on QueryClientProvider and Hydrate components passing a prop to each one.

    const App = ({ Component, pageProps }: AppProps) => {
      const [queryClient] = useState(
        () => new QueryClient({ defaultOptions: { queries: { staleTime: 30 * 1000 } } })
      )

      return (
        <QueryClientProvider client={queryClient}>
          <Hydrate state={pageProps.dehydratedState}>
            <ReactQueryDevtools initialIsOpen={false} />
            <ThemeProvider theme={theme}>
              <CssBaseline />
              <Component {...pageProps} />
            </ThemeProvider>
          </Hydrate>
        </QueryClientProvider>
      )
    }

    export default App

To start fetching data with react-query on getServerSideProps/getStaticProps you just instance a new queryClient, execute prefetchQuery and set a prop with dehydrate(queryClient).

    export async function getStaticProps() {
      const queryClient = new QueryClient()
      await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)

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

    const Home: NextPage = () => {
      const { data, isLoading } = useQuery<Todo[]>('todos', fetchTodos)
      console.log(isLoading)

      if (isLoading) return <h1>Loading...</h1>

I've created a small api that return same data as https://jsonplaceholder.typicode.com/todos but with a setTimeout of 3 seconds. The problem is that everytime i reload or move from one page to another using next/link, it takes 3 seconds to load the page. It indicates that react-query cache is not being used.

Tried moving the queryClient instance outside getServerSideProps.

Tried adding staleTime to all queries as my config shows above.

Only solution I've found was:

    export const queryClient = new QueryClient()

    export async function getStaticProps() {
      if (!queryClient.getQueryData('todos')) {
        await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)
      }

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

But there is no one talking about it and feels like i'm doing it wrong.

This is my network tab when moving to another page and going back before 30 seconds of my staleTime config and queryClient instanced outside gssp:
enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

只是偏爱你 2025-02-01 04:08:15

我一直在寻找解决这个问题的解决方案,发现此周围。在此
基本上,它检查请求来自何处。如果是来自客户端请求,getServersideProps将返回一个空对象。

export const hasNavigationCSR = (next) => async (ctx) => {
  if (ctx.req.url?.startsWith('/_next')) {
    return {
      props: {},
    };
  }
  return next?.(ctx);
};

然后,

export const getServerSideProps = hasNavigationCSR(async (ctx) => {
  const queryClient = new QueryClient()
  if (!queryClient.getQueryData('todos')) {
    await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)
  }

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

I was looking for a solution for myself to this problem and I found this work around. It was mentioned in this post.
Basically, it check where the request come from. If it's from a client side request, getServerSideProps will return an empty object.

export const hasNavigationCSR = (next) => async (ctx) => {
  if (ctx.req.url?.startsWith('/_next')) {
    return {
      props: {},
    };
  }
  return next?.(ctx);
};

Then,

export const getServerSideProps = hasNavigationCSR(async (ctx) => {
  const queryClient = new QueryClient()
  if (!queryClient.getQueryData('todos')) {
    await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)
  }

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  }
});
面犯桃花 2025-02-01 04:08:14

如果您要在getStaticProps之外创建QueryClient,则在请求和用户之间共享。那可能就是您想要的,但也可能不是您想要的。我不确定QueryClient的寿命是在getStaticProps之外创建的。

您还可以将检查,而不是进行,而是可以将staletime传递给prefetchquery。如果数据存在于缓存中,则将返回,否则,将获取新数据:

await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos, { staleTime: 1000 * 60 * 10 })

也有一个想法可以在getstaticprops/getserversideprops中新创建缓存的想法,但是用外部商店的数据预处理,例如redis缓存。请看一下此讨论: https://githbithub.com/github.com/tannerlinsley/tannerlinsley/reaeact-query/reaeact-query /讨论/3563

if you're creating the queryClient outside of getStaticProps, you're sharing it between requests and users. That might be what you want, but it also might not be what you want. I am not sure what the lifetime of a QueryClient is that gets created outside of getStaticProps though.

Instead of doing the if check, you can also pass a staleTime to prefetchQuery. If data exists in the cache, it will be returned, otherwise, new data will be fetched:

await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos, { staleTime: 1000 * 60 * 10 })

There is also the idea to newly create the cache inside getStaticProps / getServerSideProps, but prefill it with data from an external store, e.g. a redis cache. Have a look at this discussion: https://github.com/tannerlinsley/react-query/discussions/3563

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文