Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Query returns old cached data before prefetched data on re-entering the same page #8594

Closed
Iulian-Dragomirescu opened this issue Jan 28, 2025 · 1 comment

Comments

@Iulian-Dragomirescu
Copy link

Describe the bug

When navigating back to a page that uses React Query, the old cached data is shown briefly before the prefetched data from the server is displayed. This behavior is undesirable as it creates a noticeable flicker between old and new data.

The expected behavior is for React Query to exclusively use the prefetched server-side data and not render stale data upon re-entering the page.

Your minimal, reproducible example

image

Steps to reproduce

CODE:

PreFetchQuery

// import getQueryClient from "@/lib/query/getQueryClient";
import { logger } from "@/utils/logger";
import {
  dehydrate,
  HydrationBoundary,
  QueryClient,
  type UseQueryOptions,
} from "@tanstack/react-query";
import type { ReactNode } from "react";

const queryClient = new QueryClient();

export default async function PreFetchQuery({
  children,
  query,
}: {
  children: ReactNode;
  query: (UseQueryOptions & {
    disabled?: boolean;
  })[];
}) {
  // const queryClient = getQueryClient();

  for (let index = 0; index < query.length; index++) {
    const element = query[index];

    if (element.disabled) {
      logger.warn(
        `Prefetch was disabled for: '${element.queryKey.join(", ")}'`
      );
      continue;
    }

    console.log(`Prefetching: '${element.queryKey.join(", ")}'`);

    await queryClient.prefetchQuery(element);
  }

  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      {children}
    </HydrationBoundary>
  );
}

Provider

"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { useState, type ReactNode } from "react";

export default function Providers({ children }: { children: ReactNode }) {
  const [queryClient] = useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            // With SSR, we usually want to set some default staleTime
            // above 0 to avoid refetching immediately on the client
            staleTime: 60 * 1000,
            
          },
        },
      })
  );

  return (
    <QueryClientProvider client={queryClient}>
      {children}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

page.tsx

  export const dynamic = "force-dynamic";

  import PreFetchQuery from "@/lib/query/PreFetchQuery";
  import { getAdminData } from "@/utils/api";
  import type { TDataBlog } from "../../../create/[type]/types";
  import type { TBlogType } from "../../../types";
  import BlogUpdateCompoment from "./update";

  export default async function ProCreateProductPage({
    params,
  }: {
    params: Promise<{ type: TBlogType; id: string }>;
  }) {
    const { type, id } = await params;

    console.log("fetch page");

    return (
      <div className="p-5">
        <PreFetchQuery
          query={[
            {
              // disabled: true,
              queryKey: [id],
              queryFn: () =>
                getAdminData<TDataBlog>("getBlogPost", `${type}/${id}`),
            },
          ]}
        >
          <BlogUpdateCompoment type={type} id={id} />
        </PreFetchQuery>
      </div>
    );
  }

BlogUpdateComponent

  const { data } = useQuery({
    queryKey: [id],
    queryFn: () => getAdminData<TDataBlog>("getBlogPost", `${type}/${id}`),
  });

  console.log(Date.now(), data?.status);

Image

Expected behavior

As a user, I expected the prefetched server-side data to be rendered directly without showing old cached data. The prefetched data should completely replace any previous cache before the page renders.

How often does this bug happen?

None

Screenshots or Videos

No response

Platform

  • OS: Mac mini m4
  • Browser: Chrome
"@tanstack/react-query": "^5.65.1",
"@tanstack/react-query-devtools": "^5.65.1",

Tanstack Query adapter

None

TanStack Query version

5.65.1

TypeScript version

No response

Additional context

No response

@TkDodo
Copy link
Collaborator

TkDodo commented Jan 29, 2025

The expected behavior is for React Query to exclusively use the prefetched server-side data and not render stale data upon re-entering the page.

If you don’t want stale data, you’d need to either check for isFetchedAfterMount (returned from useQuery or set gcTime:0 to make sure unused data is immediately garbage collected once it becomes unused.

Just note that you will likely see a suspense fallback then in those cases.

@TkDodo TkDodo closed this as not planned Won't fix, can't repro, duplicate, stale Jan 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants